kontact

kcmkontactknt.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 <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"
KDE Home | KDE Accessibility Home | Description of Access Keys