diff options
Diffstat (limited to 'certmanager/lib/ui/backendconfigwidget.cpp')
-rw-r--r-- | certmanager/lib/ui/backendconfigwidget.cpp | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/certmanager/lib/ui/backendconfigwidget.cpp b/certmanager/lib/ui/backendconfigwidget.cpp new file mode 100644 index 000000000..c40890a43 --- /dev/null +++ b/certmanager/lib/ui/backendconfigwidget.cpp @@ -0,0 +1,323 @@ +/* -*- c++ -*- + backendconfigwidget.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2002,2004,2005 Klarälvdalens Datakonsult AB + Copyright (c) 2002,2003 Marc Mutz <mutz@kde.org> + + Libkleopatra is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + Libkleopatra is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "backendconfigwidget.h" +#include "cryptoconfigdialog.h" + +#include "kleo/cryptobackendfactory.h" +#include "ui/keylistview.h" // for lvi_cast<> + +#include <klistview.h> +#include <kdialog.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <dcopclient.h> + +#include <qpushbutton.h> +#include <qlayout.h> +#include <qheader.h> +#include <qtimer.h> + +#include <assert.h> + +namespace Kleo { + class BackendListView; +} + +class Kleo::BackendConfigWidget::Private { +public: + Kleo::BackendListView * listView; + QPushButton * configureButton; + QPushButton * rescanButton; + Kleo::CryptoBackendFactory * backendFactory; +}; + +namespace Kleo { + class BackendListViewItem; + class ProtocolCheckListItem; +} + +class Kleo::BackendListView : public KListView +{ +public: + BackendListView( BackendConfigWidget* parent, const char* name = 0 ) + : KListView( parent, name ) {} + + /// return backend for currently selected (/current) item. Used by Configure button. + const Kleo::CryptoBackend* currentBackend() const; + + /// return which protocol implementation was chosen (checked) for each type (used when saving) + const Kleo::CryptoBackend* chosenBackend( const char * protocol ); + + /// deselect all except one for a given protocol type (radiobutton-like exclusivity) + void deselectAll( const char * protocol, QCheckListItem* except ); + + void emitChanged() { static_cast<BackendConfigWidget *>( parentWidget() )->emitChanged( true ); } +}; + +// Toplevel listviewitem for a given backend (e.g. "GpgME", "Kgpg/gpg v2") +class Kleo::BackendListViewItem : public QListViewItem +{ +public: + BackendListViewItem( KListView* lv, QListViewItem *prev, const CryptoBackend *cryptoBackend ) + : QListViewItem( lv, prev, cryptoBackend->displayName() ), mCryptoBackend( cryptoBackend ) + {} + + const CryptoBackend *cryptoBackend() const { return mCryptoBackend; } + enum { RTTI = 0x2EAE3BE0, RTTI_MASK = 0xFFFFFFFF }; + int rtti() const { return RTTI; } + +private: + const CryptoBackend *mCryptoBackend; +}; + + +// Checklist item under a BackendListViewItem +// (e.g. "GpgME supports protocol OpenPGP") +class Kleo::ProtocolCheckListItem : public QCheckListItem +{ +public: + ProtocolCheckListItem( BackendListViewItem* blvi, + QListViewItem* prev, const char * protocolName, + const CryptoBackend::Protocol* protocol ) // can be 0 + : QCheckListItem( blvi, prev, itemText( protocolName, protocol ), + QCheckListItem::CheckBox ), + mProtocol( protocol ), mProtocolName( protocolName ) + {} + + enum { RTTI = 0x2EAE3BE1, RTTI_MASK = 0xFFFFFFFF }; + virtual int rtti() const { return RTTI; } + + // can be 0 + const CryptoBackend::Protocol* protocol() const { return mProtocol; } + const char * protocolName() const { return mProtocolName; } + +protected: + virtual void stateChange( bool b ) { + BackendListView* lv = static_cast<BackendListView *>( listView() ); + // "radio-button-like" behavior for the protocol checkboxes + if ( b ) + lv->deselectAll( mProtocolName, this ); + lv->emitChanged(); + QCheckListItem::stateChange( b ); + } + +private: + // Helper for the constructor. + static QString itemText( const char * protocolName, const CryptoBackend::Protocol* protocol ) { + // First one is the generic name (find a nice one for OpenPGP, SMIME) + const QString protoName = qstricmp( protocolName, "openpgp" ) != 0 + ? qstricmp( protocolName, "smime" ) != 0 + ? QString::fromLatin1( protocolName ) + : i18n( "S/MIME" ) + : i18n( "OpenPGP" ); + // second one is implementation name (gpg, gpgsm...) + const QString impName = protocol ? protocol->displayName() : i18n( "failed" ); + return i18n( "Items in Kleo::BackendConfigWidget listview (1: protocol; 2: implementation name)", + "%1 (%2)" ).arg( protoName, impName ); + } + + const CryptoBackend::Protocol* mProtocol; // can be 0 + const char * mProtocolName; +}; + +const Kleo::CryptoBackend* Kleo::BackendListView::currentBackend() const { + const QListViewItem* curItem = currentItem(); + if ( !curItem ) // can't happen + return 0; + if ( lvi_cast<Kleo::ProtocolCheckListItem>( curItem ) ) + curItem = curItem->parent(); + if ( const Kleo::BackendListViewItem * blvi = lvi_cast<Kleo::BackendListViewItem>( curItem ) ) + return blvi->cryptoBackend(); + return 0; +} + +// can't be const method due to QListViewItemIterator (why?) +const Kleo::CryptoBackend* Kleo::BackendListView::chosenBackend( const char * protocolName ) +{ + for ( QListViewItemIterator it( this /*, QListViewItemIterator::Checked doesn't work*/ ) ; + it.current() ; ++it ) + if ( ProtocolCheckListItem * p = lvi_cast<ProtocolCheckListItem>( it.current() ) ) + if ( p->isOn() && qstricmp( p->protocolName(), protocolName ) == 0 ) { + // OK that's the one. Now go up to the parent backend + // (need to do that in the listview since Protocol doesn't know it) + if ( const BackendListViewItem * parItem = lvi_cast<BackendListViewItem>( it.current()->parent() ) ) + return parItem->cryptoBackend(); + } + return 0; +} + +void Kleo::BackendListView::deselectAll( const char * protocolName, QCheckListItem* except ) +{ + for ( QListViewItemIterator it( this /*, QListViewItemIterator::Checked doesn't work*/ ) ; + it.current() ; ++it ) { + if ( it.current() == except ) continue; + if ( ProtocolCheckListItem * p = lvi_cast<ProtocolCheckListItem>( it.current() ) ) + if ( p->isOn() && qstricmp( p->protocolName(), protocolName ) == 0 ) + p->setOn( false ); + } +} + +//// + +Kleo::BackendConfigWidget::BackendConfigWidget( CryptoBackendFactory * factory, QWidget * parent, const char * name, WFlags f ) + : QWidget( parent, name, f ), d( 0 ) +{ + assert( factory ); + d = new Private(); + d->backendFactory = factory; + + QHBoxLayout * hlay = + new QHBoxLayout( this, 0, KDialog::spacingHint() ); + + d->listView = new BackendListView( this, "d->listView" ); + d->listView->addColumn( i18n("Available Backends") ); + d->listView->setAllColumnsShowFocus( true ); + d->listView->setSorting( -1 ); + d->listView->header()->setClickEnabled( false ); + d->listView->setFullWidth( true ); + + hlay->addWidget( d->listView, 1 ); + + connect( d->listView, SIGNAL(selectionChanged(QListViewItem*)), + SLOT(slotSelectionChanged(QListViewItem*)) ); + + QVBoxLayout * vlay = new QVBoxLayout( hlay ); // inherits spacing + + d->configureButton = new QPushButton( i18n("Confi&gure..."), this ); + d->configureButton->setAutoDefault( false ); + vlay->addWidget( d->configureButton ); + + connect( d->configureButton, SIGNAL(clicked()), + SLOT(slotConfigureButtonClicked()) ); + + d->rescanButton = new QPushButton( i18n("Rescan"), this ); + d->rescanButton->setAutoDefault( false ); + vlay->addWidget( d->rescanButton ); + + connect( d->rescanButton, SIGNAL(clicked()), + SLOT(slotRescanButtonClicked()) ); + + vlay->addStretch( 1 ); +} + +Kleo::BackendConfigWidget::~BackendConfigWidget() { + delete d; d = 0; +} + +void Kleo::BackendConfigWidget::load() { + d->listView->clear(); + + unsigned int backendCount = 0; + + // populate the plugin list: + BackendListViewItem * top = 0; + for ( unsigned int i = 0 ; const CryptoBackend * b = d->backendFactory->backend( i ) ; ++i ) { + + top = new Kleo::BackendListViewItem( d->listView, top, b ); + + ProtocolCheckListItem * last = 0; + for ( int i = 0 ; const char * name = b->enumerateProtocols( i ) ; ++i ) { + const CryptoBackend::Protocol * protocol = b->protocol( name ); + + if ( protocol ) { + last = new ProtocolCheckListItem( top, last, name, protocol ); + last->setOn( protocol == d->backendFactory->protocol( name ) ); + } else if ( b->supportsProtocol( name ) ) { + last = new ProtocolCheckListItem( top, last, name, 0 ); + last->setOn( false ); + last->setEnabled( false ); + } + } + + top->setOpen( true ); + ++backendCount; + } + + if ( backendCount ) { + d->listView->setCurrentItem( d->listView->firstChild() ); + d->listView->setSelected( d->listView->firstChild(), true ); + } + + slotSelectionChanged( d->listView->firstChild() ); +} + +void Kleo::BackendConfigWidget::slotSelectionChanged( QListViewItem * ) { + const CryptoBackend* backend = d->listView->currentBackend(); + if ( backend && !backend->config() ) + kdDebug(5150) << "Backend w/o config object!" << endl; + d->configureButton->setEnabled( backend && backend->config() ); +} + + +void Kleo::BackendConfigWidget::slotRescanButtonClicked() { + QStringList reasons; + d->backendFactory->scanForBackends( &reasons ); + if ( !reasons.empty() ) + KMessageBox::informationList( this, + i18n("The following problems where encountered during scanning:"), + reasons, i18n("Scan Results") ); + load(); + emit changed( true ); +} + +void Kleo::BackendConfigWidget::slotConfigureButtonClicked() { + const CryptoBackend* backend = d->listView->currentBackend(); + if ( backend && backend->config() ) { + Kleo::CryptoConfigDialog dlg( backend->config(), this ); + int result = dlg.exec(); + if ( result == QDialog::Accepted ) { + // Tell other users of gpgconf (e.g. the s/mime page) that the gpgconf data might have changed + kapp->dcopClient()->emitDCOPSignal( "KPIM::CryptoConfig", "changed()", QByteArray() ); + // and schedule a rescan, in case the updates make a backend valid + QTimer::singleShot( 0, this, SLOT(slotRescanButtonClicked()) ); + } + } + else // shouldn't happen, button is disabled + kdWarning(5150) << "Can't configure backend, no config object available" << endl; +} + +void Kleo::BackendConfigWidget::save() const { + for ( int i = 0 ; const char * name = d->backendFactory->enumerateProtocols( i ) ; ++i ) + d->backendFactory->setProtocolBackend( name, d->listView->chosenBackend( name ) ); +} + +void Kleo::BackendConfigWidget::virtual_hook( int, void* ) {} + +#include "backendconfigwidget.moc" |