kontact

newsticker/summarywidget.cpp

00001 /*
00002     This file is part of Kontact.
00003     Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 
00019     As a special exception, permission is given to link this program
00020     with any edition of Qt, and distribute the resulting executable,
00021     without including the source code for Qt in the source distribution.
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() ) { // add default
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     qApp->processEvents( QEventLoop::ExcludeUserInput |
00144                          QEventLoop::ExcludeSocketNotifiers );
00145   }
00146 
00147   updateDocuments();
00148 }
00149 
00150 void SummaryWidget::updateDocuments()
00151 {
00152   mTimer.stop();
00153 
00154   FeedList::Iterator it;
00155   for ( it = mFeeds.begin(); it != mFeeds.end(); ++it )
00156     (*it).ref.send( "refresh()" );
00157 
00158   mTimer.start( 1000 * mUpdateInterval );
00159 }
00160 
00161 void SummaryWidget::documentUpdated( DCOPRef feedRef )
00162 {
00163   ArticleMap map;
00164 
00165   int numArticles = feedRef.call( "count()" );
00166   for ( int i = 0; i < numArticles; ++i ) {
00167     DCOPRef artRef = feedRef.call( "article(int)", i );
00168     QString title, url;
00169 
00170     qApp->processEvents( QEventLoop::ExcludeUserInput |
00171                          QEventLoop::ExcludeSocketNotifiers );
00172 
00173     artRef.call( "title()" ).get( title );
00174     artRef.call( "link()" ).get( url );
00175 
00176     QPair<QString, KURL> article(title, KURL( url ));
00177     map.append( article );
00178   }
00179 
00180   FeedList::Iterator it;
00181   for ( it = mFeeds.begin(); it != mFeeds.end(); ++it )
00182     if ( (*it).ref.obj() == feedRef.obj() ) {
00183       (*it).map = map;
00184       if ( (*it).title.isEmpty() )
00185         feedRef.call( "title()" ).get( (*it).title );
00186       if ( (*it).url.isEmpty() )
00187         feedRef.call( "link()" ).get( (*it).url );
00188       if ( (*it).logo.isNull() )
00189         feedRef.call( "pixmap()" ).get( (*it).logo );
00190     }
00191 
00192   mFeedCounter++;
00193   if ( mFeedCounter == mFeeds.count() ) {
00194     mFeedCounter = 0;
00195     updateView();
00196   }
00197 }
00198 
00199 void SummaryWidget::updateView()
00200 {
00201   mLabels.setAutoDelete( true );
00202   mLabels.clear();
00203   mLabels.setAutoDelete( false );
00204 
00205   delete mLayout;
00206   mLayout = new QVBoxLayout( mBaseWidget, 3 );
00207 
00208   QFont boldFont;
00209   boldFont.setBold( true );
00210   boldFont.setPointSize( boldFont.pointSize() + 2 );
00211 
00212   FeedList::Iterator it;
00213   for ( it = mFeeds.begin(); it != mFeeds.end(); ++it ) {
00214     QHBox *hbox = new QHBox( mBaseWidget );
00215     mLayout->addWidget( hbox );
00216 
00217     // icon
00218     KURLLabel *urlLabel = new KURLLabel( hbox );
00219     urlLabel->setURL( (*it).url );
00220     urlLabel->setPixmap( (*it).logo );
00221     urlLabel->setMaximumSize( urlLabel->minimumSizeHint() );
00222     mLabels.append( urlLabel );
00223 
00224     connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
00225              kapp, SLOT( invokeBrowser( const QString& ) ) );
00226     connect( urlLabel, SIGNAL( rightClickedURL( const QString& ) ),
00227              this, SLOT( rmbMenu( const QString& ) ) );
00228 
00229     // header
00230     QLabel *label = new QLabel( hbox );
00231     label->setText( KCharsets::resolveEntities( (*it).title ) );
00232     label->setAlignment( AlignLeft|AlignVCenter );
00233     label->setFont( boldFont );
00234     label->setIndent( 6 );
00235     label->setMaximumSize( label->minimumSizeHint() );
00236     mLabels.append( label );
00237 
00238     hbox->setMaximumWidth( hbox->minimumSizeHint().width() );
00239     hbox->show();
00240 
00241     // articles
00242     ArticleMap articles = (*it).map;
00243     ArticleMap::Iterator artIt;
00244     int numArticles = 0;
00245     for ( artIt = articles.begin(); artIt != articles.end() && numArticles < mArticleCount; ++artIt ) {
00246       urlLabel = new KURLLabel( (*artIt).second.url(), (*artIt).first, mBaseWidget );
00247       urlLabel->setTextFormat( RichText );
00248       mLabels.append( urlLabel );
00249       mLayout->addWidget( urlLabel );
00250 
00251       connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
00252                kapp, SLOT( invokeBrowser( const QString& ) ) );
00253       connect( urlLabel, SIGNAL( rightClickedURL( const QString& ) ),
00254                this, SLOT( rmbMenu( const QString& ) ) );
00255 
00256 
00257       numArticles++;
00258     }
00259   }
00260 
00261   for ( QLabel *label = mLabels.first(); label; label = mLabels.next() )
00262     label->show();
00263 }
00264 
00265 void SummaryWidget::documentUpdateError( DCOPRef feedRef, int errorCode )
00266 {
00267   kdDebug() << " error while updating document, error code: " << errorCode << endl;
00268   FeedList::Iterator it;
00269   for ( it = mFeeds.begin(); it != mFeeds.end(); ++it ) {
00270     if ( (*it).ref.obj() == feedRef.obj() ) {
00271       mFeeds.remove( it );
00272       break;
00273     }
00274   }
00275 
00276   if ( mFeedCounter == mFeeds.count() ) {
00277     mFeedCounter = 0;
00278     updateView();
00279   }
00280 
00281 }
00282 
00283 QStringList SummaryWidget::configModules() const
00284 {
00285   return "kcmkontactknt.desktop";
00286 }
00287 
00288 void SummaryWidget::updateSummary( bool )
00289 {
00290   updateDocuments();
00291 }
00292 
00293 void SummaryWidget::rmbMenu( const QString& url )
00294 {
00295   QPopupMenu menu;
00296   menu.insertItem( i18n( "Copy URL to Clipboard" ) );
00297   int id = menu.exec( QCursor::pos() );
00298   if ( id != -1 )
00299     kapp->clipboard()->setText( url, QClipboard::Clipboard );
00300 }
00301 
00302 #include "summarywidget.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys