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 TQt, and distribute the resulting executable, 00021 without including the source code for TQt in the source distribution. 00022 */ 00023 00024 #include <tqclipboard.h> 00025 #include <tqeventloop.h> 00026 #include <tqhbox.h> 00027 #include <tqlayout.h> 00028 #include <tqpixmap.h> 00029 #include <tqpopupmenu.h> 00030 #include <tqcursor.h> 00031 00032 #include <dcopclient.h> 00033 #include <tdeapplication.h> 00034 #include <kcharsets.h> 00035 #include <tdeconfig.h> 00036 #include <kdebug.h> 00037 #include <tdeglobal.h> 00038 #include <kiconloader.h> 00039 #include <tdelocale.h> 00040 #include <kurllabel.h> 00041 00042 #include "summarywidget.h" 00043 00044 SummaryWidget::SummaryWidget( TQWidget *parent, const char *name ) 00045 : Kontact::Summary( parent, name ), 00046 DCOPObject( "NewsTickerPlugin" ), mLayout( 0 ), mFeedCounter( 0 ) 00047 { 00048 TQVBoxLayout *vlay = new TQVBoxLayout( this, 3, 3 ); 00049 00050 TQPixmap icon = TDEGlobal::iconLoader()->loadIcon( "kontact_news", 00051 TDEIcon::Desktop, TDEIcon::SizeMedium ); 00052 00053 TQWidget *header = createHeader( this, icon, i18n( "News Feeds" ) ); 00054 vlay->addWidget( header ); 00055 00056 TQString error; 00057 TQCString appID; 00058 00059 bool dcopAvailable = true; 00060 if ( !kapp->dcopClient()->isApplicationRegistered( "rssservice" ) ) { 00061 if ( TDEApplication::startServiceByDesktopName( "rssservice", TQStringList(), &error, &appID ) ) { 00062 TQLabel *label = new TQLabel( i18n( "No rss dcop service available.\nYou need rssservice to use this plugin." ), this ); 00063 vlay->addWidget( label, TQt::AlignHCenter ); 00064 dcopAvailable = false; 00065 } 00066 } 00067 00068 mBaseWidget = new TQWidget( this, "baseWidget" ); 00069 vlay->addWidget( mBaseWidget ); 00070 00071 connect( &mTimer, TQT_SIGNAL( timeout() ), this, TQT_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(TQString)", "documentAdded(TQString)", false ); 00081 connectDCOPSignal( 0, 0, "removed(TQString)", "documentRemoved(TQString)", false ); 00082 } 00083 00084 int SummaryWidget::summaryHeight() const 00085 { 00086 return ( mFeeds.count() == 0 ? 1 : mFeeds.count() ); 00087 } 00088 00089 void SummaryWidget::documentAdded( TQString ) 00090 { 00091 initDocuments(); 00092 } 00093 00094 void SummaryWidget::documentRemoved( TQString ) 00095 { 00096 initDocuments(); 00097 } 00098 00099 void SummaryWidget::configChanged() 00100 { 00101 readConfig(); 00102 00103 updateView(); 00104 } 00105 00106 void SummaryWidget::readConfig() 00107 { 00108 TDEConfig 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 TQStringList 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(TQString)", urls[ 0 ] ); 00126 } 00127 00128 TQStringList::Iterator it; 00129 for ( it = urls.begin(); it != urls.end(); ++it ) { 00130 DCOPRef feedRef = dcopCall.call( "document(TQString)", *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 ( tqApp ) 00144 tqApp->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput | 00145 TQEventLoop::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 TQString title, url; 00170 00171 if ( tqApp ) 00172 tqApp->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput | 00173 TQEventLoop::ExcludeSocketNotifiers ); 00174 00175 artRef.call( "title()" ).get( title ); 00176 artRef.call( "link()" ).get( url ); 00177 00178 TQPair<TQString, 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 TQVBoxLayout( mBaseWidget, 3 ); 00209 00210 TQFont 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 TQHBox *hbox = new TQHBox( mBaseWidget ); 00217 mLayout->addWidget( hbox ); 00218 00219 // icon 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, TQT_SIGNAL( leftClickedURL( const TQString& ) ), 00227 kapp, TQT_SLOT( invokeBrowser( const TQString& ) ) ); 00228 connect( urlLabel, TQT_SIGNAL( rightClickedURL( const TQString& ) ), 00229 this, TQT_SLOT( rmbMenu( const TQString& ) ) ); 00230 00231 // header 00232 TQLabel *label = new TQLabel( 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 // articles 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 //TODO: RichText causes too much horizontal space between articles 00251 //urlLabel->setTextFormat( RichText ); 00252 mLabels.append( urlLabel ); 00253 mLayout->addWidget( urlLabel ); 00254 00255 connect( urlLabel, TQT_SIGNAL( leftClickedURL( const TQString& ) ), 00256 kapp, TQT_SLOT( invokeBrowser( const TQString& ) ) ); 00257 connect( urlLabel, TQT_SIGNAL( rightClickedURL( const TQString& ) ), 00258 this, TQT_SLOT( rmbMenu( const TQString& ) ) ); 00259 00260 00261 numArticles++; 00262 } 00263 } 00264 00265 for ( TQLabel *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 TQStringList 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 TQString& url ) 00298 { 00299 TQPopupMenu menu; 00300 menu.insertItem( i18n( "Copy URL to Clipboard" ) ); 00301 int id = menu.exec( TQCursor::pos() ); 00302 if ( id != -1 ) 00303 kapp->clipboard()->setText( url, TQClipboard::Clipboard ); 00304 } 00305 00306 bool SummaryWidget::eventFilter( TQObject *obj, TQEvent* e ) 00307 { 00308 if ( obj->inherits( "KURLLabel" ) ) { 00309 KURLLabel* label = static_cast<KURLLabel*>( TQT_TQWIDGET(obj) ); 00310 if ( e->type() == TQEvent::Enter ) 00311 emit message( label->url() ); 00312 if ( e->type() == TQEvent::Leave ) 00313 emit message( TQString() ); 00314 } 00315 00316 return Kontact::Summary::eventFilter( obj, e ); 00317 } 00318 00319 #include "summarywidget.moc"