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