certmanager/lib

backendconfigwidget.cpp

00001 /*  -*- c++ -*-
00002     backendconfigwidget.cpp
00003 
00004     This file is part of libkleopatra, the KDE keymanagement library
00005     Copyright (c) 2002,2004,2005 Klarälvdalens Datakonsult AB
00006     Copyright (c) 2002,2003 Marc Mutz <mutz@kde.org>
00007 
00008     Libkleopatra is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU General Public License as
00010     published by the Free Software Foundation; either version 2 of the
00011     License, or (at your option) any later version.
00012 
00013     Libkleopatra is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016     General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021 
00022     In addition, as a special exception, the copyright holders give
00023     permission to link the code of this program with any edition of
00024     the Qt library by Trolltech AS, Norway (or with modified versions
00025     of Qt that use the same license as Qt), and distribute linked
00026     combinations including the two.  You must obey the GNU General
00027     Public License in all respects for all of the code used other than
00028     Qt.  If you modify this file, you may extend this exception to
00029     your version of the file, but you are not obligated to do so.  If
00030     you do not wish to do so, delete this exception statement from
00031     your version.
00032  */
00033 
00034 #ifdef HAVE_CONFIG_H
00035 #include <config.h>
00036 #endif
00037 
00038 #include "backendconfigwidget.h"
00039 #include "cryptoconfigdialog.h"
00040 
00041 #include "kleo/cryptobackendfactory.h"
00042 #include "ui/keylistview.h" // for lvi_cast<>
00043 
00044 #include <klistview.h>
00045 #include <kdialog.h>
00046 #include <klocale.h>
00047 #include <kdebug.h>
00048 #include <kmessagebox.h>
00049 #include <kapplication.h>
00050 #include <dcopclient.h>
00051 
00052 #include <qpushbutton.h>
00053 #include <qlayout.h>
00054 #include <qheader.h>
00055 #include <qtimer.h>
00056 
00057 #include <assert.h>
00058 
00059 namespace Kleo {
00060   class BackendListView;
00061 }
00062 
00063 class Kleo::BackendConfigWidget::Private {
00064 public:
00065   Kleo::BackendListView * listView;
00066   QPushButton * configureButton;
00067   QPushButton * rescanButton;
00068   Kleo::CryptoBackendFactory * backendFactory;
00069 };
00070 
00071 namespace Kleo {
00072   class BackendListViewItem;
00073   class ProtocolCheckListItem;
00074 }
00075 
00076 class Kleo::BackendListView : public KListView
00077 {
00078 public:
00079   BackendListView( BackendConfigWidget* parent, const char* name = 0 )
00080     : KListView( parent, name ) {}
00081 
00083   const Kleo::CryptoBackend* currentBackend() const;
00084 
00086   const Kleo::CryptoBackend* chosenBackend( const char * protocol );
00087 
00089   void deselectAll( const char * protocol, QCheckListItem* except );
00090 
00091   void emitChanged() { static_cast<BackendConfigWidget *>( parentWidget() )->emitChanged( true ); }
00092 };
00093 
00094 // Toplevel listviewitem for a given backend (e.g. "GpgME", "Kgpg/gpg v2")
00095 class Kleo::BackendListViewItem : public QListViewItem
00096 {
00097 public:
00098   BackendListViewItem( KListView* lv, QListViewItem *prev, const CryptoBackend *cryptoBackend )
00099     : QListViewItem( lv, prev, cryptoBackend->displayName() ), mCryptoBackend( cryptoBackend )
00100     {}
00101 
00102   const CryptoBackend *cryptoBackend() const { return mCryptoBackend; }
00103   enum { RTTI = 0x2EAE3BE0, RTTI_MASK = 0xFFFFFFFF };
00104   int rtti() const { return RTTI; }
00105 
00106 private:
00107   const CryptoBackend *mCryptoBackend;
00108 };
00109 
00110 
00111 // Checklist item under a BackendListViewItem
00112 // (e.g. "GpgME supports protocol OpenPGP")
00113 class Kleo::ProtocolCheckListItem : public QCheckListItem
00114 {
00115 public:
00116   ProtocolCheckListItem( BackendListViewItem* blvi,
00117                          QListViewItem* prev, const char * protocolName,
00118                          const CryptoBackend::Protocol* protocol ) // can be 0
00119     : QCheckListItem( blvi, prev, itemText( protocolName, protocol ),
00120                       QCheckListItem::CheckBox ),
00121       mProtocol( protocol ), mProtocolName( protocolName )
00122     {}
00123 
00124   enum { RTTI = 0x2EAE3BE1, RTTI_MASK = 0xFFFFFFFF };
00125   virtual int rtti() const { return RTTI; }
00126 
00127   // can be 0
00128   const CryptoBackend::Protocol* protocol() const { return mProtocol; }
00129   const char * protocolName() const { return mProtocolName; }
00130 
00131 protected:
00132   virtual void stateChange( bool b ) {
00133     BackendListView* lv = static_cast<BackendListView *>( listView() );
00134     // "radio-button-like" behavior for the protocol checkboxes
00135     if ( b )
00136       lv->deselectAll( mProtocolName, this );
00137     lv->emitChanged();
00138     QCheckListItem::stateChange( b );
00139   }
00140 
00141 private:
00142   // Helper for the constructor.
00143   static QString itemText( const char * protocolName, const CryptoBackend::Protocol* protocol ) {
00144     // First one is the generic name (find a nice one for OpenPGP, SMIME)
00145     const QString protoName = qstricmp( protocolName, "openpgp" ) != 0
00146                               ? qstricmp( protocolName, "smime" ) != 0
00147                               ? QString::fromLatin1( protocolName )
00148                               : i18n( "S/MIME" )
00149                               : i18n( "OpenPGP" );
00150     // second one is implementation name (gpg, gpgsm...)
00151     const QString impName = protocol ? protocol->displayName() : i18n( "failed" );
00152     return i18n( "Items in Kleo::BackendConfigWidget listview (1: protocol; 2: implementation name)",
00153                  "%1 (%2)" ).arg( protoName, impName );
00154   }
00155 
00156   const CryptoBackend::Protocol* mProtocol; // can be 0
00157   const char * mProtocolName;
00158 };
00159 
00160 const Kleo::CryptoBackend* Kleo::BackendListView::currentBackend() const {
00161   const QListViewItem* curItem = currentItem();
00162   if ( !curItem ) // can't happen
00163     return 0;
00164   if ( lvi_cast<Kleo::ProtocolCheckListItem>( curItem ) )
00165     curItem = curItem->parent();
00166   if ( const Kleo::BackendListViewItem * blvi = lvi_cast<Kleo::BackendListViewItem>( curItem ) )
00167     return blvi->cryptoBackend();
00168   return 0;
00169 }
00170 
00171 // can't be const method due to QListViewItemIterator (why?)
00172 const Kleo::CryptoBackend* Kleo::BackendListView::chosenBackend( const char * protocolName )
00173 {
00174   for ( QListViewItemIterator it( this /*, QListViewItemIterator::Checked doesn't work*/ ) ;
00175         it.current() ; ++it )
00176     if ( ProtocolCheckListItem * p = lvi_cast<ProtocolCheckListItem>( it.current() ) )
00177       if ( p->isOn() && qstricmp( p->protocolName(), protocolName ) == 0 ) {
00178         // OK that's the one. Now go up to the parent backend
00179         // (need to do that in the listview since Protocol doesn't know it)
00180         if ( const BackendListViewItem * parItem = lvi_cast<BackendListViewItem>( it.current()->parent() ) )
00181           return parItem->cryptoBackend();
00182       }
00183   return 0;
00184 }
00185 
00186 void Kleo::BackendListView::deselectAll( const char * protocolName, QCheckListItem* except )
00187 {
00188   for ( QListViewItemIterator it( this /*, QListViewItemIterator::Checked doesn't work*/ ) ;
00189         it.current() ; ++it ) {
00190     if ( it.current() == except ) continue;
00191     if ( ProtocolCheckListItem * p = lvi_cast<ProtocolCheckListItem>( it.current() ) )
00192       if ( p->isOn() && qstricmp( p->protocolName(), protocolName ) == 0 )
00193         p->setOn( false );
00194   }
00195 }
00196 
00198 
00199 Kleo::BackendConfigWidget::BackendConfigWidget( CryptoBackendFactory * factory, QWidget * parent, const char * name, WFlags f )
00200   : QWidget( parent, name, f ), d( 0 )
00201 {
00202   assert( factory );
00203   d = new Private();
00204   d->backendFactory = factory;
00205 
00206   QHBoxLayout * hlay =
00207     new QHBoxLayout( this, 0, KDialog::spacingHint() );
00208 
00209   d->listView = new BackendListView( this, "d->listView" );
00210   d->listView->addColumn( i18n("Available Backends") );
00211   d->listView->setAllColumnsShowFocus( true );
00212   d->listView->setSorting( -1 );
00213   d->listView->header()->setClickEnabled( false );
00214   d->listView->setFullWidth( true );
00215 
00216   hlay->addWidget( d->listView, 1 );
00217 
00218   connect( d->listView, SIGNAL(selectionChanged(QListViewItem*)),
00219        SLOT(slotSelectionChanged(QListViewItem*)) );
00220 
00221   QVBoxLayout * vlay = new QVBoxLayout( hlay ); // inherits spacing
00222 
00223   d->configureButton = new QPushButton( i18n("Confi&gure..."), this );
00224   d->configureButton->setAutoDefault( false );
00225   vlay->addWidget( d->configureButton );
00226 
00227   connect( d->configureButton, SIGNAL(clicked()),
00228        SLOT(slotConfigureButtonClicked()) );
00229 
00230   d->rescanButton = new QPushButton( i18n("Rescan"), this );
00231   d->rescanButton->setAutoDefault( false );
00232   vlay->addWidget( d->rescanButton );
00233 
00234   connect( d->rescanButton, SIGNAL(clicked()),
00235        SLOT(slotRescanButtonClicked()) );
00236 
00237   vlay->addStretch( 1 );
00238 }
00239 
00240 Kleo::BackendConfigWidget::~BackendConfigWidget() {
00241   delete d; d = 0;
00242 }
00243 
00244 void Kleo::BackendConfigWidget::load() {
00245   d->listView->clear();
00246 
00247   unsigned int backendCount = 0;
00248 
00249   // populate the plugin list:
00250   BackendListViewItem * top = 0;
00251   for ( unsigned int i = 0 ; const CryptoBackend * b = d->backendFactory->backend( i ) ; ++i ) {
00252 
00253     top = new Kleo::BackendListViewItem( d->listView, top, b );
00254 
00255     ProtocolCheckListItem * last = 0;
00256     for ( int i = 0 ; const char * name = b->enumerateProtocols( i ) ; ++i ) {
00257       const CryptoBackend::Protocol * protocol = b->protocol( name );
00258 
00259       if ( protocol ) {
00260         last = new ProtocolCheckListItem( top, last, name, protocol );
00261         last->setOn( protocol == d->backendFactory->protocol( name ) );
00262       } else if ( b->supportsProtocol( name ) ) {
00263         last = new ProtocolCheckListItem( top, last, name, 0 );
00264         last->setOn( false );
00265         last->setEnabled( false );
00266       }
00267     }
00268 
00269     top->setOpen( true );
00270     ++backendCount;
00271   }
00272 
00273   if ( backendCount ) {
00274     d->listView->setCurrentItem( d->listView->firstChild() );
00275     d->listView->setSelected( d->listView->firstChild(), true );
00276   }
00277 
00278   slotSelectionChanged( d->listView->firstChild() );
00279 }
00280 
00281 void Kleo::BackendConfigWidget::slotSelectionChanged( QListViewItem * ) {
00282   const CryptoBackend* backend = d->listView->currentBackend();
00283   if ( backend && !backend->config() )
00284     kdDebug(5150) << "Backend w/o config object!" << endl;
00285   d->configureButton->setEnabled( backend && backend->config() );
00286 }
00287 
00288 
00289 void Kleo::BackendConfigWidget::slotRescanButtonClicked() {
00290   QStringList reasons;
00291   d->backendFactory->scanForBackends( &reasons );
00292   if ( !reasons.empty() )
00293     KMessageBox::informationList( this,
00294                   i18n("The following problems where encountered during scanning:"),
00295                   reasons, i18n("Scan Results") );
00296   load();
00297   emit changed( true );
00298 }
00299 
00300 void Kleo::BackendConfigWidget::slotConfigureButtonClicked() {
00301   const CryptoBackend* backend = d->listView->currentBackend();
00302   if ( backend && backend->config() ) {
00303     Kleo::CryptoConfigDialog dlg( backend->config(), this );
00304     int result = dlg.exec();
00305     if ( result == QDialog::Accepted ) {
00306       // Tell other users of gpgconf (e.g. the s/mime page) that the gpgconf data might have changed
00307       kapp->dcopClient()->emitDCOPSignal( "KPIM::CryptoConfig", "changed()", QByteArray() );
00308       // and schedule a rescan, in case the updates make a backend valid
00309       QTimer::singleShot( 0, this, SLOT(slotRescanButtonClicked()) );
00310     }
00311   }
00312   else // shouldn't happen, button is disabled
00313     kdWarning(5150) << "Can't configure backend, no config object available" << endl;
00314 }
00315 
00316 void Kleo::BackendConfigWidget::save() const {
00317   for ( int i = 0 ; const char * name = d->backendFactory->enumerateProtocols( i ) ; ++i )
00318     d->backendFactory->setProtocolBackend( name,  d->listView->chosenBackend( name ) );
00319 }
00320 
00321 void Kleo::BackendConfigWidget::virtual_hook( int, void* ) {}
00322 
00323 #include "backendconfigwidget.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys