4 * Copyright (c) 2000, 2001, 2007 Frerich Raabe <raabe@kde.org>
6 * This program is distributed in the hope that it will be useful, but WITHOUT
7 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8 * FOR A PARTICULAR PURPOSE. For licensing and distribution details, check the
9 * accompanying file 'COPYING'.
11 #include "knewsticker.h"
12 #include "feedsettingswidget.h"
13 #include "newsfeedmanager.h"
15 #include "ui_visualsettings.h"
16 #include "itemviews.h"
18 #include <kconfigdialog.h>
19 #include <kiconloader.h>
20 #include <kmimetype.h>
21 #include <syndication/item.h>
23 #include <QDesktopServices>
24 #include <QGraphicsSceneContextMenuEvent>
26 #include <QMessageBox>
27 #include <QSignalMapper>
30 using namespace Syndication
;
32 static QString
unescape( const QString
&s
)
35 t
.replace( QLatin1String( "&" ), QLatin1String( "&" ) );
36 t
.replace( QLatin1String( """ ), QLatin1String( "'" ) );
37 t
.replace( QLatin1String( "'" ), QLatin1String( "\"" ) );
38 t
.replace( QLatin1String( "<" ), QLatin1String( "<" ) );
39 t
.replace( QLatin1String( ">" ), QLatin1String( ">" ) );
43 KNewsTicker::KNewsTicker( QObject
*parent
, const QVariantList
&args
)
44 : Plasma::Applet( parent
, args
),
48 setDrawStandardBackground( true );
51 connect( NewsFeedManager::self(), SIGNAL( feedLoaded( const QUrl
& ) ),
52 this, SLOT( feedLoaded( const QUrl
& ) ) );
53 connect( NewsFeedManager::self(), SIGNAL( updateFinished() ),
54 this, SLOT( feedUpdateFinished() ) );
56 NewsFeedManager::self()->setSubscriptions( Settings::feedUrls() );
58 m_updateTimer
= new QTimer( this );
59 connect( m_updateTimer
, SIGNAL( timeout() ),
60 this, SLOT( updateFeeds() ) );
61 m_updateTimer
->start( Settings::updateInterval() * 60 * 1000 );
63 setHasConfigurationInterface( true );
68 void KNewsTicker::showConfigurationInterface()
70 KConfigDialog
dlg( 0, "settings", Settings::self() );
71 connect( &dlg
, SIGNAL( settingsChanged( const QString
& ) ),
72 this, SLOT( settingsChanged( const QString
& ) ) );
73 dlg
.setFaceType( KPageDialog::Tabbed
);
75 QWidget
*page
= new QWidget( 0 );
77 Ui::VisualSettings ui
;
80 dlg
.addPage( page
, i18n( "Appearance" ) );
82 FeedSettingsWidget
*feedSettingsWidget
= new FeedSettingsWidget( 0 );
83 dlg
.addPage( feedSettingsWidget
, i18n( "Feed Access" ) );
85 QFont origFont
= Settings::font();
86 const QStringList origFeedUrls
= Settings::feedUrls();
88 if ( dlg
.exec() == QDialog::Accepted
) {
89 Settings::setFeedUrls( feedSettingsWidget
->feedUrls() );
91 if ( Settings::feedUrls() != origFeedUrls
) {
92 NewsFeedManager::self()->setSubscriptions( Settings::feedUrls() );
100 void KNewsTicker::settingsChanged( const QString
& /* dialogName */ )
105 QSizeF
KNewsTicker::contentSizeHint() const
107 return m_itemView
->boundingRect().size();
110 QList
<QAction
*> KNewsTicker::contextActions()
112 QList
<QAction
*> actions
;
114 delete m_signalMapper
;
115 m_signalMapper
= new QSignalMapper( this );
116 connect( m_signalMapper
, SIGNAL( mapped( const QString
& ) ),
117 this, SLOT( openFeedItem( const QString
& ) ) );
119 QList
<FeedPtr
> availableFeeds
= NewsFeedManager::self()->availableFeeds().values();
120 foreach ( FeedPtr feed
, availableFeeds
) {
121 QMenu
*feedMenu
= new QMenu
;
122 QList
<ItemPtr
> items
= feed
->items();
123 foreach ( ItemPtr item
, items
) {
124 QString title
= unescape( item
->title() );
125 title
.replace( "&", "&" );
126 QAction
*itemAction
= feedMenu
->addAction( title
,
127 m_signalMapper
, SLOT( map() ) );
129 m_signalMapper
->setMapping( itemAction
, item
->link() );
132 QAction
*feedAction
= new QAction( feed
->title(), 0 );
133 const QString favIcon
= KMimeType::favIconForUrl( feed
->link() );
134 if ( !favIcon
.isEmpty() ) {
135 feedAction
->setIcon( SmallIcon( favIcon
) );
137 feedAction
->setMenu( feedMenu
);
138 actions
.append( feedAction
);
144 bool KNewsTicker::hideArticle( const QUrl
&url
)
146 return Settings::hideReadArticles() && m_readArticles
.contains( url
);
149 void KNewsTicker::feedLoaded( const QUrl
&url
)
151 FeedPtr feed
= NewsFeedManager::self()->availableFeeds()[ url
];
152 foreach ( ItemPtr item
, feed
->items() ) {
154 i
.text
= unescape( item
->title() );
155 i
.url
= item
->link();
156 i
.description
= unescape( item
->description() );
161 void KNewsTicker::feedUpdateFinished()
163 /* Filter out unneded entries in our m_readArticles set; first find out
164 * which URLs are shown after the update. Then, create a new list of read
165 * articles in which only those articles get added which are available
169 foreach ( const NewsItem
&item
, m_items
) {
170 allUrls
.insert( item
.url
);
173 QSet
<QUrl
> activeReadArticles
;
174 foreach ( const QUrl
&readUrl
, m_readArticles
) {
175 if ( allUrls
.contains( readUrl
) ) {
176 activeReadArticles
.insert( readUrl
);
179 m_readArticles
= activeReadArticles
;
181 m_itemView
->setItems( m_items
);
184 void KNewsTicker::updateFeeds()
187 NewsFeedManager::self()->update();
190 void KNewsTicker::openFeedItem( const QString
&url
)
192 QDesktopServices::openUrl( url
);
193 if ( !m_readArticles
.contains( url
) ) {
194 m_readArticles
.insert( url
);
198 void KNewsTicker::reloadSettings()
201 m_updateTimer
->setInterval( Settings::updateInterval() * 60 * 1000 );
204 void KNewsTicker::setupItemView()
207 switch ( Settings::displayStyle() ) {
208 case Settings::EnumDisplayStyle::ScrollingText
:
209 m_itemView
= new ScrollingItemView( this );
211 case Settings::EnumDisplayStyle::PagedText
:
212 m_itemView
= new PagingItemView( this );
214 case Settings::EnumDisplayStyle::COUNT
:
215 // Just used internally by KConfigXT
218 connect( m_itemView
, SIGNAL( itemActivated( const QString
& ) ),
219 this, SLOT( openFeedItem( const QString
& ) ) );
220 m_itemView
->setRect( 0, 0, 512, QFontMetrics( Settings::font() ).height() * 2 );
221 m_itemView
->reloadSettings();
222 m_itemView
->setItems( m_items
);
225 K_EXPORT_PLASMA_APPLET(knewsticker
, KNewsTicker
)
227 #include "knewsticker.moc"