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
00026
00027
00028
00029
00030
00031
00032
00033 #include <config-kleopatra.h>
00034
00035 #include "certificateselectiondialog.h"
00036
00037 #include <view/searchbar.h>
00038 #include <view/tabwidget.h>
00039
00040 #include <models/keylistmodel.h>
00041 #include <models/keycache.h>
00042
00043 #include <commands/reloadkeyscommand.h>
00044 #include <commands/lookupcertificatescommand.h>
00045 #include <commands/newcertificatecommand.h>
00046
00047 #include <gpgme++/key.h>
00048
00049 #include <KLocale>
00050 #include <KConfigGroup>
00051 #include <KSharedConfig>
00052 #include <KDebug>
00053
00054 #include <QLabel>
00055 #include <QPushButton>
00056 #include <QDialogButtonBox>
00057 #include <QLayout>
00058 #include <QItemSelectionModel>
00059 #include <QAbstractItemView>
00060 #include <QPointer>
00061
00062 #include <boost/bind.hpp>
00063
00064 #include <algorithm>
00065
00066 using namespace Kleo;
00067 using namespace Kleo::Dialogs;
00068 using namespace Kleo::Commands;
00069 using namespace boost;
00070 using namespace GpgME;
00071
00072 class CertificateSelectionDialog::Private {
00073 friend class ::Kleo::Dialogs::CertificateSelectionDialog;
00074 CertificateSelectionDialog * const q;
00075 public:
00076 explicit Private( CertificateSelectionDialog * qq );
00077
00078
00079 private:
00080 void reload() {
00081 ( new ReloadKeysCommand( 0 ) )->start();
00082 }
00083 void create() {
00084 NewCertificateCommand * cmd = new NewCertificateCommand( 0 );
00085 if ( ( options & AnyFormat ) != AnyFormat )
00086 cmd->setProtocol( (options & OpenPGPFormat) ? OpenPGP : CMS );
00087 cmd->start();
00088 }
00089 void lookup() {
00090 ( new LookupCertificatesCommand( 0 ) )->start();
00091 }
00092 void slotKeysMayHaveChanged();
00093 void slotCurrentViewChanged( QAbstractItemView * newView );
00094 void slotSelectionChanged();
00095 void slotDoubleClicked( const QModelIndex & idx );
00096
00097 private:
00098 bool acceptable( const std::vector<Key> & keys ) {
00099 return !keys.empty();
00100 }
00101 void filterAllowedKeys( std::vector<Key> & keys );
00102 void updateLabelText() {
00103 ui.label.setText( !customLabelText.isEmpty() ? customLabelText :
00104 (options & MultiSelection)
00105 ? i18n( "Please select one or more of the following certificates:" )
00106 : i18n( "Please select one of the following certificates:" ) );
00107 }
00108
00109 private:
00110 QPointer<QAbstractItemView> lastView;
00111 QString customLabelText;
00112 Options options;
00113
00114 struct UI {
00115 QLabel label;
00116 SearchBar searchBar;
00117 TabWidget tabWidget;
00118 QDialogButtonBox buttonBox;
00119 QVBoxLayout vlay;
00120
00121 explicit UI( CertificateSelectionDialog * q )
00122 : label( q ),
00123 searchBar( q ),
00124 tabWidget( q ),
00125 buttonBox( q ),
00126 vlay( q )
00127 {
00128 KDAB_SET_OBJECT_NAME( label );
00129 KDAB_SET_OBJECT_NAME( searchBar );
00130 KDAB_SET_OBJECT_NAME( tabWidget );
00131 KDAB_SET_OBJECT_NAME( buttonBox );
00132 KDAB_SET_OBJECT_NAME( vlay );
00133
00134 vlay.addWidget( &label );
00135 vlay.addWidget( &searchBar );
00136 vlay.addWidget( &tabWidget, 1 );
00137 vlay.addWidget( &buttonBox );
00138
00139 QPushButton * const ok = buttonBox.addButton( QDialogButtonBox::Ok );
00140 ok->setEnabled( false );
00141 QPushButton * const cancel = buttonBox.addButton( QDialogButtonBox::Close );
00142 QPushButton * const reload = buttonBox.addButton( i18n("Reload"), QDialogButtonBox::ActionRole );
00143 QPushButton * const lookup = buttonBox.addButton( i18n("Lookup..."), QDialogButtonBox::ActionRole );
00144 QPushButton * const create = buttonBox.addButton( i18n("New..."), QDialogButtonBox::ActionRole );
00145
00146 lookup->setToolTip( i18nc("@info:tooltip","Lookup certificates on server") );
00147 reload->setToolTip( i18nc("@info:tooltip","Refresh certificate list") );
00148 create->setToolTip( i18nc("@info:tooltip","Create a new certificate") );
00149
00150 connect( &buttonBox, SIGNAL(accepted()), q, SLOT(accept()) );
00151 connect( &buttonBox, SIGNAL(rejected()), q, SLOT(reject()) );
00152 connect( reload, SIGNAL(clicked()), q, SLOT(reload()) );
00153 connect( lookup, SIGNAL(clicked()), q, SLOT(lookup()) );
00154 connect( create, SIGNAL(clicked()), q, SLOT(create()) );
00155 connect( KeyCache::instance().get(), SIGNAL(keysMayHaveChanged()),
00156 q, SLOT(slotKeysMayHaveChanged()) );
00157 }
00158 } ui;
00159 };
00160
00161
00162 CertificateSelectionDialog::Private::Private( CertificateSelectionDialog * qq )
00163 : q( qq ),
00164 ui( q )
00165 {
00166 ui.tabWidget.setFlatModel( AbstractKeyListModel::createFlatKeyListModel() );
00167 ui.tabWidget.setHierarchicalModel( AbstractKeyListModel::createHierarchicalKeyListModel() );
00168 ui.tabWidget.connectSearchBar( &ui.searchBar );
00169
00170 connect( &ui.tabWidget, SIGNAL(currentViewChanged(QAbstractItemView*)),
00171 q, SLOT(slotCurrentViewChanged(QAbstractItemView*)) );
00172
00173 updateLabelText();
00174 q->setWindowTitle( i18n( "Certificate Selection" ) );
00175 }
00176
00177 CertificateSelectionDialog::CertificateSelectionDialog( QWidget * parent, Qt::WindowFlags f )
00178 : QDialog( parent, f ), d( new Private( this ) )
00179 {
00180 const KSharedConfig::Ptr config = KSharedConfig::openConfig( "kleopatracertificateselectiondialogrc" );
00181 d->ui.tabWidget.loadViews( config.data() );
00182 const KConfigGroup geometry( config, "Geometry" );
00183 resize( geometry.readEntry( "size", size() ) );
00184 d->slotKeysMayHaveChanged();
00185 }
00186
00187 CertificateSelectionDialog::~CertificateSelectionDialog() {}
00188
00189 void CertificateSelectionDialog::setCustomLabelText( const QString & txt ) {
00190 if ( txt == d->customLabelText )
00191 return;
00192 d->customLabelText = txt;
00193 d->updateLabelText();
00194 }
00195
00196 QString CertificateSelectionDialog::customLabelText() const {
00197 return d->customLabelText;
00198 }
00199
00200 void CertificateSelectionDialog::setOptions( Options options ) {
00201 if ( d->options == options )
00202 return;
00203 d->options = options;
00204
00205 d->ui.tabWidget.setMultiSelection( options & MultiSelection );
00206
00207 d->slotKeysMayHaveChanged();
00208 }
00209
00210 CertificateSelectionDialog::Options CertificateSelectionDialog::options() const {
00211 return d->options;
00212 }
00213
00214 void CertificateSelectionDialog::setStringFilter( const QString & filter ) {
00215 d->ui.tabWidget.setStringFilter( filter );
00216 }
00217
00218 void CertificateSelectionDialog::setKeyFilter( const shared_ptr<KeyFilter> & filter ) {
00219 d->ui.tabWidget.setKeyFilter( filter );
00220 }
00221
00222 void CertificateSelectionDialog::selectCertificates( const std::vector<Key> & keys ) {
00223 const QAbstractItemView * const view = d->ui.tabWidget.currentView();
00224 if ( !view )
00225 return;
00226 const KeyListModelInterface * const model = dynamic_cast<KeyListModelInterface*>( view->model() );
00227 assert( model );
00228 QItemSelectionModel * const sm = view->selectionModel();
00229 assert( sm );
00230
00231 Q_FOREACH( const QModelIndex & idx, model->indexes( keys ) )
00232 if ( idx.isValid() )
00233 sm->select( idx, QItemSelectionModel::Select | QItemSelectionModel::Rows );
00234 }
00235
00236 void CertificateSelectionDialog::selectCertificate( const Key & key ) {
00237 selectCertificates( std::vector<Key>( 1, key ) );
00238 }
00239
00240 std::vector<Key> CertificateSelectionDialog::selectedCertificates() const {
00241 const QAbstractItemView * const view = d->ui.tabWidget.currentView();
00242 if ( !view )
00243 return std::vector<Key>();
00244 const KeyListModelInterface * const model = dynamic_cast<KeyListModelInterface*>( view->model() );
00245 assert( model );
00246 const QItemSelectionModel * const sm = view->selectionModel();
00247 assert( sm );
00248 return model->keys( sm->selectedRows() );
00249 }
00250
00251 Key CertificateSelectionDialog::selectedCertificate() const {
00252 const std::vector<Key> keys = selectedCertificates();
00253 return keys.empty() ? Key() : keys.front() ;
00254 }
00255
00256 void CertificateSelectionDialog::hideEvent( QHideEvent * e ) {
00257 KSharedConfig::Ptr config = KSharedConfig::openConfig( "kleopatracertificateselectiondialogrc" );
00258 d->ui.tabWidget.saveViews( config.data() );
00259 KConfigGroup geometry( config, "Geometry" );
00260 geometry.writeEntry( "size", size() );
00261 QDialog::hideEvent( e );
00262 }
00263
00264 void CertificateSelectionDialog::Private::slotKeysMayHaveChanged() {
00265 q->setEnabled( true );
00266 std::vector<Key> keys = (options & SecretKeys) ? KeyCache::instance()->secretKeys() : KeyCache::instance()->keys() ;
00267 filterAllowedKeys( keys );
00268 const std::vector<Key> selected = q->selectedCertificates();
00269 if ( AbstractKeyListModel * const model = ui.tabWidget.flatModel() )
00270 model->setKeys( keys );
00271 if ( AbstractKeyListModel * const model = ui.tabWidget.hierarchicalModel() )
00272 model->setKeys( keys );
00273 q->selectCertificates( selected );
00274 }
00275
00276 void CertificateSelectionDialog::Private::filterAllowedKeys( std::vector<Key> & keys ) {
00277 std::vector<Key>::iterator end = keys.end();
00278
00279 switch ( options & AnyFormat ) {
00280 case OpenPGPFormat:
00281 end = std::remove_if( keys.begin(), end, bind( &Key::protocol, _1 ) != GpgME::OpenPGP );
00282 break;
00283 case CMSFormat:
00284 end = std::remove_if( keys.begin(), end, bind( &Key::protocol, _1 ) != GpgME::CMS );
00285 break;
00286 default:
00287 case AnyFormat:
00288 ;
00289 }
00290
00291 switch ( options & AnyCertificate ) {
00292 case SignOnly:
00293 end = std::remove_if( keys.begin(), end, !bind( &Key::canSign, _1 ) );
00294 break;
00295 case EncryptOnly:
00296 end = std::remove_if( keys.begin(), end, !bind( &Key::canEncrypt, _1 ) );
00297 break;
00298 default:
00299 case AnyCertificate:
00300 ;
00301 }
00302
00303 if ( options & SecretKeys )
00304 end = std::remove_if( keys.begin(), end, !bind( &Key::hasSecret, _1 ) );
00305
00306 keys.erase( end, keys.end() );
00307 }
00308
00309 void CertificateSelectionDialog::Private::slotCurrentViewChanged( QAbstractItemView * newView ) {
00310 if ( lastView ) {
00311 disconnect( lastView, SIGNAL(doubleClicked(QModelIndex)),
00312 q, SLOT(slotDoubleClicked(QModelIndex)) );
00313 assert( lastView->selectionModel() );
00314 disconnect( lastView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
00315 q, SLOT(slotSelectionChanged()) );
00316 }
00317 lastView = newView;
00318 if ( newView ) {
00319 connect( newView, SIGNAL(doubleClicked(QModelIndex)),
00320 q, SLOT(slotDoubleClicked(QModelIndex)) );
00321 assert( newView->selectionModel() );
00322 connect( newView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
00323 q, SLOT(slotSelectionChanged()) );
00324 }
00325 slotSelectionChanged();
00326 }
00327
00328 void CertificateSelectionDialog::Private::slotSelectionChanged() {
00329 if ( QPushButton * const pb = ui.buttonBox.button( QDialogButtonBox::Ok ) )
00330 pb->setEnabled( acceptable( q->selectedCertificates() ) );
00331 }
00332
00333 void CertificateSelectionDialog::Private::slotDoubleClicked( const QModelIndex & idx ) {
00334 QAbstractItemView * const view = ui.tabWidget.currentView();
00335 assert( view );
00336 const KeyListModelInterface * const model = dynamic_cast<KeyListModelInterface*>( view->model() );
00337 assert( model );
00338 QItemSelectionModel * const sm = view->selectionModel();
00339 assert( sm );
00340 sm->select( idx, QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Rows );
00341 QMetaObject::invokeMethod( q, "accept", Qt::QueuedConnection );
00342 }
00343
00344 void CertificateSelectionDialog::accept() {
00345 if ( d->acceptable( selectedCertificates() ) )
00346 QDialog::accept();
00347 }
00348
00349 #include "moc_certificateselectiondialog.cpp"