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 <qgroupbox.h>
00025 #include <qlabel.h>
00026 #include <qlayout.h>
00027 #include <qlineedit.h>
00028 #include <qvaluevector.h>
00029 #include <qspinbox.h>
00030
00031 #include <dcopref.h>
00032 #include <dcopclient.h>
00033
00034 #include <kaboutdata.h>
00035 #include <kapplication.h>
00036 #include <kaccelmanager.h>
00037 #include <kconfig.h>
00038 #include <kdebug.h>
00039 #include <kdialogbase.h>
00040 #include <klistview.h>
00041 #include <klocale.h>
00042 #include <kpushbutton.h>
00043
00044 #include "kcmkontactknt.h"
00045
00046 #include "newsfeeds.h"
00047
00048 #include <kdepimmacros.h>
00049
00050 extern "C"
00051 {
00052 KDE_EXPORT KCModule *create_kontactknt( QWidget *parent, const char * )
00053 {
00054 return new KCMKontactKNT( parent, "kcmkontactknt" );
00055 }
00056 }
00057
00058 NewsEditDialog::NewsEditDialog( const QString& title, const QString& url, QWidget *parent )
00059 : KDialogBase( Plain, i18n( "New News Feed" ), Ok | Cancel,
00060 Ok, parent, 0, true, true )
00061 {
00062 QWidget *page = plainPage();
00063 QGridLayout *layout = new QGridLayout( page, 2, 3, marginHint(),
00064 spacingHint() );
00065
00066 QLabel *label = new QLabel( i18n( "Name:" ), page );
00067 layout->addWidget( label, 0, 0 );
00068
00069 mTitle = new QLineEdit( page );
00070 label->setBuddy( mTitle );
00071 layout->addMultiCellWidget( mTitle, 0, 0, 1, 2 );
00072
00073 label = new QLabel( i18n( "URL:" ), page );
00074 layout->addWidget( label, 1, 0 );
00075
00076 mURL = new QLineEdit( page );
00077 label->setBuddy( mURL );
00078 layout->addMultiCellWidget( mURL, 1, 1, 1, 2 );
00079
00080 mTitle->setText( title );
00081 mURL->setText( url );
00082 mTitle->setFocus();
00083 connect( mTitle, SIGNAL( textChanged( const QString& ) ),
00084 this, SLOT( modified() ) );
00085 connect( mURL, SIGNAL( textChanged( const QString& ) ),
00086 this, SLOT( modified() ) );
00087
00088 modified();
00089 }
00090
00091 void NewsEditDialog::modified()
00092 {
00093 enableButton( KDialogBase::Ok, !title().isEmpty() && !url().isEmpty() );
00094 }
00095
00096 QString NewsEditDialog::title() const
00097 {
00098 return mTitle->text();
00099 }
00100
00101 QString NewsEditDialog::url() const
00102 {
00103 return mURL->text();
00104 }
00105
00106 class NewsItem : public QListViewItem
00107 {
00108 public:
00109 NewsItem( QListView *parent, const QString& title, const QString& url, bool custom )
00110 : QListViewItem( parent ), mTitle( title ), mUrl( url ), mCustom( custom )
00111 {
00112 setText( 0, mTitle );
00113 }
00114
00115 NewsItem( QListViewItem *parent, const QString& title, const QString& url, bool custom )
00116 : QListViewItem( parent ), mTitle( title ), mUrl( url ), mCustom( custom )
00117 {
00118 setText( 0, mTitle );
00119 }
00120
00121 QString title() const { return mTitle; }
00122 QString url() const { return mUrl; }
00123 bool custom() const { return mCustom; }
00124
00125 private:
00126 QString mTitle;
00127 QString mUrl;
00128 bool mCustom;
00129 };
00130
00131 KCMKontactKNT::KCMKontactKNT( QWidget *parent, const char *name )
00132 : KCModule( parent, name )
00133 {
00134 initGUI();
00135
00136 connect( mAllNews, SIGNAL( currentChanged( QListViewItem* ) ),
00137 this, SLOT( allCurrentChanged( QListViewItem* ) ) );
00138 connect( mSelectedNews, SIGNAL( selectionChanged( QListViewItem* ) ),
00139 this, SLOT( selectedChanged( QListViewItem* ) ) );
00140
00141 connect( mUpdateInterval, SIGNAL( valueChanged( int ) ), SLOT( modified() ) );
00142 connect( mArticleCount, SIGNAL( valueChanged( int ) ), SLOT( modified() ) );
00143
00144 connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addNews() ) );
00145 connect( mRemoveButton, SIGNAL( clicked() ), this, SLOT( removeNews() ) );
00146 connect( mNewButton, SIGNAL( clicked() ), this, SLOT( newFeed() ) );
00147 connect( mDeleteButton, SIGNAL( clicked() ), this, SLOT( deleteFeed() ) );
00148
00149 KAcceleratorManager::manage( this );
00150
00151 load();
00152 }
00153
00154 void KCMKontactKNT::loadNews()
00155 {
00156 QValueVector<QListViewItem*> parents;
00157 QValueVector<QListViewItem*>::Iterator it;
00158
00159 parents.append( new QListViewItem( mAllNews, i18n( "Arts" ) ) );
00160 parents.append( new QListViewItem( mAllNews, i18n( "Business" ) ) );
00161 parents.append( new QListViewItem( mAllNews, i18n( "Computers" ) ) );
00162 parents.append( new QListViewItem( mAllNews, i18n( "Misc" ) ) );
00163 parents.append( new QListViewItem( mAllNews, i18n( "Recreation" ) ) );
00164 parents.append( new QListViewItem( mAllNews, i18n( "Society" ) ) );
00165
00166 for ( it = parents.begin(); it != parents.end(); ++it )
00167 (*it)->setSelectable( false );
00168
00169 for ( int i = 0; i < DEFAULT_NEWSSOURCES; ++i ) {
00170 NewsSourceData data = NewsSourceDefault[ i ];
00171 new NewsItem( parents[ data.category() ], data.name(), data.url(), false );
00172 mFeedMap.insert( data.url(), data.name() );
00173 }
00174 }
00175
00176 void KCMKontactKNT::loadCustomNews()
00177 {
00178 KConfig config( "kcmkontactkntrc" );
00179 QMap<QString, QString> customFeeds = config.entryMap( "CustomFeeds" );
00180 config.setGroup( "CustomFeeds" );
00181
00182 mCustomItem = new QListViewItem( mAllNews, i18n( "Custom" ) );
00183 mCustomItem->setSelectable( false );
00184
00185 if ( customFeeds.count() == 0 )
00186 mCustomItem->setVisible( false );
00187
00188 QMap<QString, QString>::Iterator it;
00189 for ( it = customFeeds.begin(); it != customFeeds.end(); ++it ) {
00190 QStringList value = config.readListEntry( it.key() );
00191 mCustomFeeds.append( new NewsItem( mCustomItem, value[ 0 ], value[ 1 ], true ) );
00192 mFeedMap.insert( value[ 1 ], value[ 0 ] );
00193 mCustomItem->setVisible( true );
00194 }
00195 }
00196
00197 void KCMKontactKNT::storeCustomNews()
00198 {
00199 KConfig config( "kcmkontactkntrc" );
00200 config.deleteGroup( "CustomFeeds" );
00201 config.setGroup( "CustomFeeds" );
00202
00203 int counter = 0;
00204 QValueList<NewsItem*>::Iterator it;
00205 for ( it = mCustomFeeds.begin(); it != mCustomFeeds.end(); ++it ) {
00206 QStringList value;
00207 value << (*it)->title() << (*it)->url();
00208 config.writeEntry( QString::number( counter ), value );
00209
00210 ++counter;
00211 }
00212
00213 config.sync();
00214 }
00215
00216 void KCMKontactKNT::addNews()
00217 {
00218 if ( !dcopActive() )
00219 return;
00220
00221 NewsItem *item = dynamic_cast<NewsItem*>( mAllNews->selectedItem() );
00222 if ( item == 0 )
00223 return;
00224
00225 DCOPRef service( "rssservice", "RSSService" );
00226 service.send( "add(QString)", item->url() );
00227
00228 scanNews();
00229
00230 emit changed( true );
00231 }
00232
00233 void KCMKontactKNT::removeNews()
00234 {
00235 if ( !dcopActive() )
00236 return;
00237
00238 NewsItem *item = dynamic_cast<NewsItem*>( mSelectedNews->selectedItem() );
00239 if ( item == 0 )
00240 return;
00241
00242 DCOPRef service( "rssservice", "RSSService" );
00243 service.send( "remove(QString)", item->url() );
00244
00245 scanNews();
00246
00247 emit changed( true );
00248 }
00249
00250 void KCMKontactKNT::newFeed()
00251 {
00252 NewsEditDialog dlg( "", "", this );
00253
00254 if ( dlg.exec() ) {
00255 NewsItem *item = new NewsItem( mCustomItem, dlg.title(), dlg.url(), true );
00256 mCustomFeeds.append( item );
00257 mFeedMap.insert( dlg.url(), dlg.title() );
00258
00259 mCustomItem->setVisible( true );
00260 mCustomItem->setOpen( true );
00261 mAllNews->ensureItemVisible( item );
00262 mAllNews->setSelected( item, true );
00263
00264 emit changed( true );
00265 }
00266 }
00267
00268 void KCMKontactKNT::deleteFeed()
00269 {
00270 NewsItem *item = dynamic_cast<NewsItem*>( mAllNews->selectedItem() );
00271 if ( !item )
00272 return;
00273
00274 if ( mCustomFeeds.find( item ) == mCustomFeeds.end() )
00275 return;
00276
00277 mCustomFeeds.remove( item );
00278 mFeedMap.remove( item->url() );
00279 delete item;
00280
00281 if ( mCustomFeeds.count() == 0 )
00282 mCustomItem->setVisible( false );
00283
00284 emit changed( true );
00285 }
00286
00287 void KCMKontactKNT::scanNews()
00288 {
00289 if ( !dcopActive() )
00290 return;
00291
00292 mSelectedNews->clear();
00293
00294 DCOPRef service( "rssservice", "RSSService" );
00295 QStringList urls = service.call( "list()" );
00296
00297 for ( uint i = 0; i < urls.count(); ++i )
00298 {
00299 QString url = urls[ i ];
00300 QString feedName = mFeedMap[ url ];
00301 if ( feedName.isEmpty() )
00302 feedName = url;
00303 new NewsItem( mSelectedNews, feedName, url, false );
00304 }
00305 }
00306
00307 void KCMKontactKNT::selectedChanged( QListViewItem *item )
00308 {
00309 mRemoveButton->setEnabled( item && item->isSelected() );
00310 }
00311
00312 void KCMKontactKNT::allCurrentChanged( QListViewItem *item )
00313 {
00314 NewsItem *newsItem = dynamic_cast<NewsItem*>( item );
00315
00316 bool addState = false;
00317 bool delState = false;
00318 if ( newsItem && newsItem->isSelected() ) {
00319 addState = true;
00320 delState = (mCustomFeeds.find( newsItem ) != mCustomFeeds.end());
00321 }
00322
00323 mAddButton->setEnabled( addState );
00324 mDeleteButton->setEnabled( delState );
00325 }
00326
00327 void KCMKontactKNT::modified()
00328 {
00329 emit changed( true );
00330 }
00331
00332 void KCMKontactKNT::initGUI()
00333 {
00334 QGridLayout *layout = new QGridLayout( this, 2, 3, KDialog::marginHint(),
00335 KDialog::spacingHint() );
00336
00337 mAllNews = new KListView( this );
00338 mAllNews->addColumn( i18n( "All" ) );
00339 mAllNews->setRootIsDecorated( true );
00340 mAllNews->setFullWidth( true );
00341 layout->addWidget( mAllNews, 0, 0 );
00342
00343 QVBoxLayout *vbox = new QVBoxLayout( layout, KDialog::spacingHint() );
00344
00345 vbox->addStretch();
00346 mAddButton = new KPushButton( i18n( "Add" ), this );
00347 mAddButton->setEnabled( false );
00348 vbox->addWidget( mAddButton );
00349 mRemoveButton = new KPushButton( i18n( "Remove" ), this );
00350 mRemoveButton->setEnabled( false );
00351 vbox->addWidget( mRemoveButton );
00352 vbox->addStretch();
00353
00354 mSelectedNews = new KListView( this );
00355 mSelectedNews->addColumn( i18n( "Selected" ) );
00356 mSelectedNews->setFullWidth( true );
00357 layout->addWidget( mSelectedNews, 0, 2 );
00358
00359 QGroupBox *box = new QGroupBox( 0, Qt::Vertical,
00360 i18n( "News Feed Settings" ), this );
00361
00362 QGridLayout *boxLayout = new QGridLayout( box->layout(), 2, 3,
00363 KDialog::spacingHint() );
00364
00365 QLabel *label = new QLabel( i18n( "Refresh time:" ), box );
00366 boxLayout->addWidget( label, 0, 0 );
00367
00368 mUpdateInterval = new QSpinBox( 1, 3600, 1, box );
00369 mUpdateInterval->setSuffix( " sec." );
00370 label->setBuddy( mUpdateInterval );
00371 boxLayout->addWidget( mUpdateInterval, 0, 1 );
00372
00373 label = new QLabel( i18n( "Number of items shown:" ), box );
00374 boxLayout->addWidget( label, 1, 0 );
00375
00376 mArticleCount = new QSpinBox( box );
00377 label->setBuddy( mArticleCount );
00378 boxLayout->addWidget( mArticleCount, 1, 1 );
00379
00380 mNewButton = new KPushButton( i18n( "New Feed..." ), box );
00381 boxLayout->addWidget( mNewButton, 0, 2 );
00382
00383 mDeleteButton = new KPushButton( i18n( "Delete Feed" ), box );
00384 mDeleteButton->setEnabled( false );
00385 boxLayout->addWidget( mDeleteButton, 1, 2 );
00386
00387 layout->addMultiCellWidget( box, 1, 1, 0, 2 );
00388 }
00389
00390 bool KCMKontactKNT::dcopActive() const
00391 {
00392 QString error;
00393 QCString appID;
00394 bool isGood = true;
00395 DCOPClient *client = kapp->dcopClient();
00396 if ( !client->isApplicationRegistered( "rssservice" ) ) {
00397 if ( KApplication::startServiceByDesktopName( "rssservice", QStringList(), &error, &appID ) )
00398 isGood = false;
00399 }
00400
00401 return isGood;
00402 }
00403
00404 void KCMKontactKNT::load()
00405 {
00406 mAllNews->clear();
00407
00408 loadNews();
00409 loadCustomNews();
00410 scanNews();
00411
00412 KConfig config( "kcmkontactkntrc" );
00413 config.setGroup( "General" );
00414
00415 mUpdateInterval->setValue( config.readNumEntry( "UpdateInterval", 600 ) );
00416 mArticleCount->setValue( config.readNumEntry( "ArticleCount", 4 ) );
00417
00418 emit changed( false );
00419 }
00420
00421 void KCMKontactKNT::save()
00422 {
00423 storeCustomNews();
00424
00425 KConfig config( "kcmkontactkntrc" );
00426 config.setGroup( "General" );
00427
00428 config.writeEntry( "UpdateInterval", mUpdateInterval->value() );
00429 config.writeEntry( "ArticleCount", mArticleCount->value() );
00430
00431 config.sync();
00432
00433 emit changed( false );
00434 }
00435
00436 void KCMKontactKNT::defaults()
00437 {
00438 }
00439
00440 const KAboutData* KCMKontactKNT::aboutData() const
00441 {
00442 KAboutData *about = new KAboutData( I18N_NOOP( "kcmkontactknt" ),
00443 I18N_NOOP( "Newsticker Configuration Dialog" ),
00444 0, 0, KAboutData::License_GPL,
00445 I18N_NOOP( "(c) 2003 - 2004 Tobias Koenig" ) );
00446
00447 about->addAuthor( "Tobias Koenig", 0, "tokoe@kde.org" );
00448
00449 return about;
00450 }
00451
00452 #include "kcmkontactknt.moc"