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