00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <qclipboard.h>
00025 #include <qeventloop.h>
00026 #include <qhbox.h>
00027 #include <qlayout.h>
00028 #include <qpixmap.h>
00029 #include <qpopupmenu.h>
00030 #include <qcursor.h>
00031
00032 #include <dcopclient.h>
00033 #include <kapplication.h>
00034 #include <kcharsets.h>
00035 #include <kconfig.h>
00036 #include <kdebug.h>
00037 #include <kglobal.h>
00038 #include <kiconloader.h>
00039 #include <klocale.h>
00040 #include <kurllabel.h>
00041
00042 #include "summarywidget.h"
00043
00044 SummaryWidget::SummaryWidget( QWidget *parent, const char *name )
00045 : Kontact::Summary( parent, name ),
00046 DCOPObject( "NewsTickerPlugin" ), mLayout( 0 ), mFeedCounter( 0 )
00047 {
00048 QVBoxLayout *vlay = new QVBoxLayout( this, 3, 3 );
00049
00050 QPixmap icon = KGlobal::iconLoader()->loadIcon( "kontact_news",
00051 KIcon::Desktop, KIcon::SizeMedium );
00052
00053 QWidget *header = createHeader( this, icon, i18n( "News Feeds" ) );
00054 vlay->addWidget( header );
00055
00056 QString error;
00057 QCString appID;
00058
00059 bool dcopAvailable = true;
00060 if ( !kapp->dcopClient()->isApplicationRegistered( "rssservice" ) ) {
00061 if ( KApplication::startServiceByDesktopName( "rssservice", QStringList(), &error, &appID ) ) {
00062 QLabel *label = new QLabel( i18n( "No rss dcop service available.\nYou need rssservice to use this plugin." ), this );
00063 vlay->addWidget( label, Qt::AlignHCenter );
00064 dcopAvailable = false;
00065 }
00066 }
00067
00068 mBaseWidget = new QWidget( this, "baseWidget" );
00069 vlay->addWidget( mBaseWidget );
00070
00071 connect( &mTimer, SIGNAL( timeout() ), this, SLOT( updateDocuments() ) );
00072
00073 readConfig();
00074
00075 connectDCOPSignal( 0, 0, "documentUpdateError(DCOPRef,int)", "documentUpdateError(DCOPRef, int)", false );
00076
00077 if ( dcopAvailable )
00078 initDocuments();
00079
00080 connectDCOPSignal( 0, 0, "added(QString)", "documentAdded(QString)", false );
00081 connectDCOPSignal( 0, 0, "removed(QString)", "documentRemoved(QString)", false );
00082 }
00083
00084 int SummaryWidget::summaryHeight() const
00085 {
00086 return ( mFeeds.count() == 0 ? 1 : mFeeds.count() );
00087 }
00088
00089 void SummaryWidget::documentAdded( QString )
00090 {
00091 initDocuments();
00092 }
00093
00094 void SummaryWidget::documentRemoved( QString )
00095 {
00096 initDocuments();
00097 }
00098
00099 void SummaryWidget::configChanged()
00100 {
00101 readConfig();
00102
00103 updateView();
00104 }
00105
00106 void SummaryWidget::readConfig()
00107 {
00108 KConfig config( "kcmkontactkntrc" );
00109 config.setGroup( "General" );
00110
00111 mUpdateInterval = config.readNumEntry( "UpdateInterval", 600 );
00112 mArticleCount = config.readNumEntry( "ArticleCount", 4 );
00113 }
00114
00115 void SummaryWidget::initDocuments()
00116 {
00117 mFeeds.clear();
00118
00119 DCOPRef dcopCall( "rssservice", "RSSService" );
00120 QStringList urls;
00121 dcopCall.call( "list()" ).get( urls );
00122
00123 if ( urls.isEmpty() ) {
00124 urls.append( "http://www.kde.org/dotkdeorg.rdf" );
00125 dcopCall.send( "add(QString)", urls[ 0 ] );
00126 }
00127
00128 QStringList::Iterator it;
00129 for ( it = urls.begin(); it != urls.end(); ++it ) {
00130 DCOPRef feedRef = dcopCall.call( "document(QString)", *it );
00131
00132 Feed feed;
00133 feed.ref = feedRef;
00134 feedRef.call( "title()" ).get( feed.title );
00135 feedRef.call( "link()" ).get( feed.url );
00136 feedRef.call( "pixmap()" ).get( feed.logo );
00137 mFeeds.append( feed );
00138
00139 disconnectDCOPSignal( "rssservice", feedRef.obj(), "documentUpdated(DCOPRef)", 0 );
00140 connectDCOPSignal( "rssservice", feedRef.obj(), "documentUpdated(DCOPRef)",
00141 "documentUpdated(DCOPRef)", false );
00142
00143 if ( qApp )
00144 qApp->eventLoop()->processEvents( QEventLoop::ExcludeUserInput |
00145 QEventLoop::ExcludeSocketNotifiers );
00146 }
00147
00148 updateDocuments();
00149 }
00150
00151 void SummaryWidget::updateDocuments()
00152 {
00153 mTimer.stop();
00154
00155 FeedList::Iterator it;
00156 for ( it = mFeeds.begin(); it != mFeeds.end(); ++it )
00157 (*it).ref.send( "refresh()" );
00158
00159 mTimer.start( 1000 * mUpdateInterval );
00160 }
00161
00162 void SummaryWidget::documentUpdated( DCOPRef feedRef )
00163 {
00164 ArticleMap map;
00165
00166 int numArticles = feedRef.call( "count()" );
00167 for ( int i = 0; i < numArticles; ++i ) {
00168 DCOPRef artRef = feedRef.call( "article(int)", i );
00169 QString title, url;
00170
00171 if ( qApp )
00172 qApp->eventLoop()->processEvents( QEventLoop::ExcludeUserInput |
00173 QEventLoop::ExcludeSocketNotifiers );
00174
00175 artRef.call( "title()" ).get( title );
00176 artRef.call( "link()" ).get( url );
00177
00178 QPair<QString, KURL> article(title, KURL( url ));
00179 map.append( article );
00180 }
00181
00182 FeedList::Iterator it;
00183 for ( it = mFeeds.begin(); it != mFeeds.end(); ++it )
00184 if ( (*it).ref.obj() == feedRef.obj() ) {
00185 (*it).map = map;
00186 if ( (*it).title.isEmpty() )
00187 feedRef.call( "title()" ).get( (*it).title );
00188 if ( (*it).url.isEmpty() )
00189 feedRef.call( "link()" ).get( (*it).url );
00190 if ( (*it).logo.isNull() )
00191 feedRef.call( "pixmap()" ).get( (*it).logo );
00192 }
00193
00194 mFeedCounter++;
00195 if ( mFeedCounter == mFeeds.count() ) {
00196 mFeedCounter = 0;
00197 updateView();
00198 }
00199 }
00200
00201 void SummaryWidget::updateView()
00202 {
00203 mLabels.setAutoDelete( true );
00204 mLabels.clear();
00205 mLabels.setAutoDelete( false );
00206
00207 delete mLayout;
00208 mLayout = new QVBoxLayout( mBaseWidget, 3 );
00209
00210 QFont boldFont;
00211 boldFont.setBold( true );
00212 boldFont.setPointSize( boldFont.pointSize() + 2 );
00213
00214 FeedList::Iterator it;
00215 for ( it = mFeeds.begin(); it != mFeeds.end(); ++it ) {
00216 QHBox *hbox = new QHBox( mBaseWidget );
00217 mLayout->addWidget( hbox );
00218
00219
00220 KURLLabel *urlLabel = new KURLLabel( hbox );
00221 urlLabel->setURL( (*it).url );
00222 urlLabel->setPixmap( (*it).logo );
00223 urlLabel->setMaximumSize( urlLabel->minimumSizeHint() );
00224 mLabels.append( urlLabel );
00225
00226 connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
00227 kapp, SLOT( invokeBrowser( const QString& ) ) );
00228 connect( urlLabel, SIGNAL( rightClickedURL( const QString& ) ),
00229 this, SLOT( rmbMenu( const QString& ) ) );
00230
00231
00232 QLabel *label = new QLabel( hbox );
00233 label->setText( KCharsets::resolveEntities( (*it).title ) );
00234 label->setAlignment( AlignLeft|AlignVCenter );
00235 label->setFont( boldFont );
00236 label->setIndent( 6 );
00237 label->setMaximumSize( label->minimumSizeHint() );
00238 mLabels.append( label );
00239
00240 hbox->setMaximumWidth( hbox->minimumSizeHint().width() );
00241 hbox->show();
00242
00243
00244 ArticleMap articles = (*it).map;
00245 ArticleMap::Iterator artIt;
00246 int numArticles = 0;
00247 for ( artIt = articles.begin(); artIt != articles.end() && numArticles < mArticleCount; ++artIt ) {
00248 urlLabel = new KURLLabel( (*artIt).second.url(), (*artIt).first, mBaseWidget );
00249 urlLabel->installEventFilter( this );
00250
00251
00252 mLabels.append( urlLabel );
00253 mLayout->addWidget( urlLabel );
00254
00255 connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
00256 kapp, SLOT( invokeBrowser( const QString& ) ) );
00257 connect( urlLabel, SIGNAL( rightClickedURL( const QString& ) ),
00258 this, SLOT( rmbMenu( const QString& ) ) );
00259
00260
00261 numArticles++;
00262 }
00263 }
00264
00265 for ( QLabel *label = mLabels.first(); label; label = mLabels.next() )
00266 label->show();
00267 }
00268
00269 void SummaryWidget::documentUpdateError( DCOPRef feedRef, int errorCode )
00270 {
00271 kdDebug() << " error while updating document, error code: " << errorCode << endl;
00272 FeedList::Iterator it;
00273 for ( it = mFeeds.begin(); it != mFeeds.end(); ++it ) {
00274 if ( (*it).ref.obj() == feedRef.obj() ) {
00275 mFeeds.remove( it );
00276 break;
00277 }
00278 }
00279
00280 if ( mFeedCounter == mFeeds.count() ) {
00281 mFeedCounter = 0;
00282 updateView();
00283 }
00284
00285 }
00286
00287 QStringList SummaryWidget::configModules() const
00288 {
00289 return "kcmkontactknt.desktop";
00290 }
00291
00292 void SummaryWidget::updateSummary( bool )
00293 {
00294 updateDocuments();
00295 }
00296
00297 void SummaryWidget::rmbMenu( const QString& url )
00298 {
00299 QPopupMenu menu;
00300 menu.insertItem( i18n( "Copy URL to Clipboard" ) );
00301 int id = menu.exec( QCursor::pos() );
00302 if ( id != -1 )
00303 kapp->clipboard()->setText( url, QClipboard::Clipboard );
00304 }
00305
00306 bool SummaryWidget::eventFilter( QObject *obj, QEvent* e )
00307 {
00308 if ( obj->inherits( "KURLLabel" ) ) {
00309 KURLLabel* label = static_cast<KURLLabel*>( obj );
00310 if ( e->type() == QEvent::Enter )
00311 emit message( label->url() );
00312 if ( e->type() == QEvent::Leave )
00313 emit message( QString::null );
00314 }
00315
00316 return Kontact::Summary::eventFilter( obj, e );
00317 }
00318
00319 #include "summarywidget.moc"