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 "newsfeedmanager.h"
14 #include "itemviews.h"
15 #include "settingsdialog.h"
17 #include <kconfigdialog.h>
18 #include <kiconloader.h>
19 #include <kmimetype.h>
20 #include <syndication/item.h>
22 #include <QDesktopServices>
23 #include <QGraphicsSceneContextMenuEvent>
25 #include <QMessageBox>
26 #include <QSignalMapper>
29 using namespace Syndication
;
31 static QString
unescape( const QString
&s
)
34 t
.replace( QLatin1String( "&" ), QLatin1String( "&" ) );
35 t
.replace( QLatin1String( """ ), QLatin1String( "'" ) );
36 t
.replace( QLatin1String( "'" ), QLatin1String( "\"" ) );
37 t
.replace( QLatin1String( "<" ), QLatin1String( "<" ) );
38 t
.replace( QLatin1String( ">" ), QLatin1String( ">" ) );
42 KNewsTicker::KNewsTicker( QObject
*parent
, const QVariantList
&args
)
43 : Plasma::Applet( parent
, args
),
48 setBackgroundHints( DefaultBackground
);
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 KNewsTicker::~KNewsTicker()
70 delete m_settingsDialog
;
73 void KNewsTicker::showConfigurationInterface()
75 if ( !m_settingsDialog
) {
76 m_settingsDialog
= new SettingsDialog
;
77 connect( m_settingsDialog
, SIGNAL( settingsChanged( const QString
& ) ),
78 this, SLOT( settingsChanged( const QString
& ) ) );
79 connect( m_settingsDialog
, SIGNAL( accepted() ),
80 this, SLOT( settingsAccepted() ) );
82 m_settingsDialog
->show();
85 void KNewsTicker::settingsChanged( const QString
& /* dialogName */ )
90 void KNewsTicker::settingsAccepted()
92 Settings::setFeedUrls( m_settingsDialog
->feedUrls() );
93 NewsFeedManager::self()->setSubscriptions( Settings::feedUrls() );
98 QSizeF
KNewsTicker::contentSizeHint() const
100 return m_itemView
->boundingRect().size();
103 QList
<QAction
*> KNewsTicker::contextActions()
105 QList
<QAction
*> actions
;
107 delete m_signalMapper
;
108 m_signalMapper
= new QSignalMapper( this );
109 connect( m_signalMapper
, SIGNAL( mapped( const QString
& ) ),
110 this, SLOT( openFeedItem( const QString
& ) ) );
112 QList
<FeedPtr
> availableFeeds
= NewsFeedManager::self()->availableFeeds().values();
113 foreach ( FeedPtr feed
, availableFeeds
) {
114 QMenu
*feedMenu
= new QMenu
;
115 QList
<ItemPtr
> items
= feed
->items();
116 foreach ( ItemPtr item
, items
) {
117 QString title
= unescape( item
->title() );
118 title
.replace( "&", "&" );
119 QAction
*itemAction
= feedMenu
->addAction( title
,
120 m_signalMapper
, SLOT( map() ) );
122 m_signalMapper
->setMapping( itemAction
, item
->link() );
125 QAction
*feedAction
= new QAction( feed
->title(), 0 );
126 const QString favIcon
= KMimeType::favIconForUrl( feed
->link() );
127 if ( !favIcon
.isEmpty() ) {
128 feedAction
->setIcon( SmallIcon( favIcon
) );
130 feedAction
->setMenu( feedMenu
);
131 actions
.append( feedAction
);
137 bool KNewsTicker::hideArticle( const QUrl
&url
)
139 return Settings::hideReadArticles() && m_readArticles
.contains( url
);
142 void KNewsTicker::feedLoaded( const QUrl
&url
)
144 FeedPtr feed
= NewsFeedManager::self()->availableFeeds()[ url
];
145 foreach ( ItemPtr item
, feed
->items() ) {
147 i
.text
= unescape( item
->title() );
148 i
.url
= item
->link();
149 i
.description
= unescape( item
->description() );
154 void KNewsTicker::feedUpdateFinished()
156 /* Filter out unneded entries in our m_readArticles set; first find out
157 * which URLs are shown after the update. Then, create a new list of read
158 * articles in which only those articles get added which are available
162 foreach ( const NewsItem
&item
, m_items
) {
163 allUrls
.insert( item
.url
);
166 QSet
<QUrl
> activeReadArticles
;
167 foreach ( const QUrl
&readUrl
, m_readArticles
) {
168 if ( allUrls
.contains( readUrl
) ) {
169 activeReadArticles
.insert( readUrl
);
172 m_readArticles
= activeReadArticles
;
174 m_itemView
->setItems( m_items
);
177 void KNewsTicker::updateFeeds()
180 NewsFeedManager::self()->update();
183 void KNewsTicker::openFeedItem( const QString
&url
)
185 QDesktopServices::openUrl( url
);
186 if ( !m_readArticles
.contains( url
) ) {
187 m_readArticles
.insert( url
);
191 void KNewsTicker::reloadSettings()
194 m_updateTimer
->setInterval( Settings::updateInterval() * 60 * 1000 );
197 void KNewsTicker::setupItemView()
201 switch ( Settings::displayStyle() ) {
202 case Settings::EnumDisplayStyle::ScrollingText
:
203 m_itemView
= new ScrollingItemView( this );
205 case Settings::EnumDisplayStyle::PagedText
:
206 m_itemView
= new PagingItemView( this );
208 case Settings::EnumDisplayStyle::COUNT
:
209 // Just used internally by KConfigXT
213 connect( m_itemView
, SIGNAL( itemActivated( const QString
& ) ),
214 this, SLOT( openFeedItem( const QString
& ) ) );
215 m_itemView
->setRect( 0, 0, 512, QFontMetrics( Settings::font() ).height() * 2 );
216 m_itemView
->reloadSettings();
217 m_itemView
->setItems( m_items
);
220 K_EXPORT_PLASMA_APPLET(knewsticker
, KNewsTicker
)
222 #include "knewsticker.moc"