certmanager/lib

backendconfigwidget.cpp
1 /*
2  backendconfigwidget.cpp
3 
4  This file is part of libkleopatra, the KDE keymanagement library
5  Copyright (c) 2002,2004,2005 Klarälvdalens Datakonsult AB
6  Copyright (c) 2002,2003 Marc Mutz <mutz@kde.org>
7 
8  Libkleopatra is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version.
12 
13  Libkleopatra is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22  In addition, as a special exception, the copyright holders give
23  permission to link the code of this program with any edition of
24  the TQt library by Trolltech AS, Norway (or with modified versions
25  of TQt that use the same license as TQt), and distribute linked
26  combinations including the two. You must obey the GNU General
27  Public License in all respects for all of the code used other than
28  TQt. If you modify this file, you may extend this exception to
29  your version of the file, but you are not obligated to do so. If
30  you do not wish to do so, delete this exception statement from
31  your version.
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 
38 #include "backendconfigwidget.h"
39 #include "cryptoconfigdialog.h"
40 
41 #include "kleo/cryptobackendfactory.h"
42 #include "ui/keylistview.h" // for lvi_cast<>
43 
44 #include <tdelistview.h>
45 #include <kdialog.h>
46 #include <tdelocale.h>
47 #include <kdebug.h>
48 #include <tdemessagebox.h>
49 #include <tdeapplication.h>
50 #include <dcopclient.h>
51 
52 #include <tqpushbutton.h>
53 #include <tqlayout.h>
54 #include <tqheader.h>
55 #include <tqtimer.h>
56 
57 #include <assert.h>
58 
59 namespace Kleo {
60  class BackendListView;
61 }
62 
63 class Kleo::BackendConfigWidget::Private {
64 public:
65  Kleo::BackendListView * listView;
66  TQPushButton * configureButton;
67  TQPushButton * rescanButton;
68  Kleo::CryptoBackendFactory * backendFactory;
69 };
70 
71 namespace Kleo {
72  class BackendListViewItem;
73  class ProtocolCheckListItem;
74 }
75 
76 class Kleo::BackendListView : public TDEListView
77 {
78 public:
79  BackendListView( BackendConfigWidget* parent, const char* name = 0 )
80  : TDEListView( parent, name ) {}
81 
83  const Kleo::CryptoBackend* currentBackend() const;
84 
86  const Kleo::CryptoBackend* chosenBackend( const char * protocol );
87 
89  void deselectAll( const char * protocol, TQCheckListItem* except );
90 
91  void emitChanged() { static_cast<BackendConfigWidget *>( parentWidget() )->emitChanged( true ); }
92 };
93 
94 // Toplevel listviewitem for a given backend (e.g. "GpgME", "Kgpg/gpg v2")
95 class Kleo::BackendListViewItem : public TQListViewItem
96 {
97 public:
98  BackendListViewItem( TDEListView* lv, TQListViewItem *prev, const CryptoBackend *cryptoBackend )
99  : TQListViewItem( lv, prev, cryptoBackend->displayName() ), mCryptoBackend( cryptoBackend )
100  {}
101 
102  const CryptoBackend *cryptoBackend() const { return mCryptoBackend; }
103  enum { RTTI = 0x2EAE3BE0, RTTI_MASK = 0xFFFFFFFF };
104  int rtti() const { return RTTI; }
105 
106 private:
107  const CryptoBackend *mCryptoBackend;
108 };
109 
110 
111 // Checklist item under a BackendListViewItem
112 // (e.g. "GpgME supports protocol OpenPGP")
113 class Kleo::ProtocolCheckListItem : public TQCheckListItem
114 {
115 public:
116  ProtocolCheckListItem( BackendListViewItem* blvi,
117  TQListViewItem* prev, const char * protocolName,
118  const CryptoBackend::Protocol* protocol ) // can be 0
119  : TQCheckListItem( blvi, prev, itemText( protocolName, protocol ),
120  TQCheckListItem::CheckBox ),
121  mProtocol( protocol ), mProtocolName( protocolName )
122  {}
123 
124  enum { RTTI = 0x2EAE3BE1, RTTI_MASK = 0xFFFFFFFF };
125  virtual int rtti() const { return RTTI; }
126 
127  // can be 0
128  const CryptoBackend::Protocol* protocol() const { return mProtocol; }
129  const char * protocolName() const { return mProtocolName; }
130 
131 protected:
132  virtual void stateChange( bool b ) {
133  BackendListView* lv = static_cast<BackendListView *>( listView() );
134  // "radio-button-like" behavior for the protocol checkboxes
135  if ( b )
136  lv->deselectAll( mProtocolName, this );
137  lv->emitChanged();
138  TQCheckListItem::stateChange( b );
139  }
140 
141 private:
142  // Helper for the constructor.
143  static TQString itemText( const char * protocolName, const CryptoBackend::Protocol* protocol ) {
144  // First one is the generic name (find a nice one for OpenPGP, SMIME)
145  const TQString protoName = tqstricmp( protocolName, "openpgp" ) != 0
146  ? tqstricmp( protocolName, "smime" ) != 0
147  ? TQString::fromLatin1( protocolName )
148  : i18n( "S/MIME" )
149  : i18n( "OpenPGP" );
150  // second one is implementation name (gpg, gpgsm...)
151  const TQString impName = protocol ? protocol->displayName() : i18n( "failed" );
152  return i18n( "Items in Kleo::BackendConfigWidget listview (1: protocol; 2: implementation name)",
153  "%1 (%2)" ).arg( protoName, impName );
154  }
155 
156  const CryptoBackend::Protocol* mProtocol; // can be 0
157  const char * mProtocolName;
158 };
159 
160 const Kleo::CryptoBackend* Kleo::BackendListView::currentBackend() const {
161  const TQListViewItem* curItem = currentItem();
162  if ( !curItem ) // can't happen
163  return 0;
164  if ( lvi_cast<Kleo::ProtocolCheckListItem>( curItem ) )
165  curItem = curItem->parent();
166  if ( const Kleo::BackendListViewItem * blvi = lvi_cast<Kleo::BackendListViewItem>( curItem ) )
167  return blvi->cryptoBackend();
168  return 0;
169 }
170 
171 // can't be const method due to TQListViewItemIterator (why?)
172 const Kleo::CryptoBackend* Kleo::BackendListView::chosenBackend( const char * protocolName )
173 {
174  for ( TQListViewItemIterator it( this /*, TQListViewItemIterator::Checked doesn't work*/ ) ;
175  it.current() ; ++it )
176  if ( ProtocolCheckListItem * p = lvi_cast<ProtocolCheckListItem>( it.current() ) )
177  if ( p->isOn() && tqstricmp( p->protocolName(), protocolName ) == 0 ) {
178  // OK that's the one. Now go up to the parent backend
179  // (need to do that in the listview since Protocol doesn't know it)
180  if ( const BackendListViewItem * parItem = lvi_cast<BackendListViewItem>( it.current()->parent() ) )
181  return parItem->cryptoBackend();
182  }
183  return 0;
184 }
185 
186 void Kleo::BackendListView::deselectAll( const char * protocolName, TQCheckListItem* except )
187 {
188  for ( TQListViewItemIterator it( this /*, TQListViewItemIterator::Checked doesn't work*/ ) ;
189  it.current() ; ++it ) {
190  if ( it.current() == except ) continue;
191  if ( ProtocolCheckListItem * p = lvi_cast<ProtocolCheckListItem>( it.current() ) )
192  if ( p->isOn() && tqstricmp( p->protocolName(), protocolName ) == 0 )
193  p->setOn( false );
194  }
195 }
196 
198 
199 Kleo::BackendConfigWidget::BackendConfigWidget( CryptoBackendFactory * factory, TQWidget * parent, const char * name, WFlags f )
200  : TQWidget( parent, name, f ), d( 0 )
201 {
202  assert( factory );
203  d = new Private();
204  d->backendFactory = factory;
205 
206  TQHBoxLayout * hlay =
207  new TQHBoxLayout( this, 0, KDialog::spacingHint() );
208 
209  d->listView = new BackendListView( this, "d->listView" );
210  d->listView->addColumn( i18n("Available Backends") );
211  d->listView->setAllColumnsShowFocus( true );
212  d->listView->setSorting( -1 );
213  d->listView->header()->setClickEnabled( false );
214  d->listView->setFullWidth( true );
215 
216  hlay->addWidget( d->listView, 1 );
217 
218  connect( d->listView, TQ_SIGNAL(selectionChanged(TQListViewItem*)),
219  TQ_SLOT(slotSelectionChanged(TQListViewItem*)) );
220 
221  TQVBoxLayout * vlay = new TQVBoxLayout( hlay ); // inherits spacing
222 
223  d->configureButton = new TQPushButton( i18n("Confi&gure..."), this );
224  d->configureButton->setAutoDefault( false );
225  vlay->addWidget( d->configureButton );
226 
227  connect( d->configureButton, TQ_SIGNAL(clicked()),
228  TQ_SLOT(slotConfigureButtonClicked()) );
229 
230  d->rescanButton = new TQPushButton( i18n("Rescan"), this );
231  d->rescanButton->setAutoDefault( false );
232  vlay->addWidget( d->rescanButton );
233 
234  connect( d->rescanButton, TQ_SIGNAL(clicked()),
235  TQ_SLOT(slotRescanButtonClicked()) );
236 
237  vlay->addStretch( 1 );
238 }
239 
240 Kleo::BackendConfigWidget::~BackendConfigWidget() {
241  delete d; d = 0;
242 }
243 
244 void Kleo::BackendConfigWidget::load() {
245  d->listView->clear();
246 
247  unsigned int backendCount = 0;
248 
249  // populate the plugin list:
250  BackendListViewItem * top = 0;
251  for ( unsigned int i = 0 ; const CryptoBackend * b = d->backendFactory->backend( i ) ; ++i ) {
252 
253  top = new Kleo::BackendListViewItem( d->listView, top, b );
254 
255  ProtocolCheckListItem * last = 0;
256  for ( int i = 0 ; const char * name = b->enumerateProtocols( i ) ; ++i ) {
257  const CryptoBackend::Protocol * protocol = b->protocol( name );
258 
259  if ( protocol ) {
260  last = new ProtocolCheckListItem( top, last, name, protocol );
261  last->setOn( protocol == d->backendFactory->protocol( name ) );
262  } else if ( b->supportsProtocol( name ) ) {
263  last = new ProtocolCheckListItem( top, last, name, 0 );
264  last->setOn( false );
265  last->setEnabled( false );
266  }
267  }
268 
269  top->setOpen( true );
270  ++backendCount;
271  }
272 
273  if ( backendCount ) {
274  d->listView->setCurrentItem( d->listView->firstChild() );
275  d->listView->setSelected( d->listView->firstChild(), true );
276  }
277 
278  slotSelectionChanged( d->listView->firstChild() );
279 }
280 
281 void Kleo::BackendConfigWidget::slotSelectionChanged( TQListViewItem * ) {
282  const CryptoBackend* backend = d->listView->currentBackend();
283  if ( backend && !backend->config() )
284  kdDebug(5150) << "Backend w/o config object!" << endl;
285  d->configureButton->setEnabled( backend && backend->config() );
286 }
287 
288 
289 void Kleo::BackendConfigWidget::slotRescanButtonClicked() {
290  TQStringList reasons;
291  d->backendFactory->scanForBackends( &reasons );
292  if ( !reasons.empty() )
293  KMessageBox::informationList( this,
294  i18n("The following problems where encountered during scanning:"),
295  reasons, i18n("Scan Results") );
296  load();
297  emit changed( true );
298 }
299 
300 void Kleo::BackendConfigWidget::slotConfigureButtonClicked() {
301  const CryptoBackend* backend = d->listView->currentBackend();
302  if ( backend && backend->config() ) {
303  Kleo::CryptoConfigDialog dlg( backend->config(), this );
304  int result = dlg.exec();
305  if ( result == TQDialog::Accepted ) {
306  // Tell other users of gpgconf (e.g. the s/mime page) that the gpgconf data might have changed
307  kapp->dcopClient()->emitDCOPSignal( "KPIM::CryptoConfig", "changed()", TQByteArray() );
308  // and schedule a rescan, in case the updates make a backend valid
309  TQTimer::singleShot( 0, this, TQ_SLOT(slotRescanButtonClicked()) );
310  }
311  }
312  else // shouldn't happen, button is disabled
313  kdWarning(5150) << "Can't configure backend, no config object available" << endl;
314 }
315 
316 void Kleo::BackendConfigWidget::save() const {
317  for ( int i = 0 ; const char * name = d->backendFactory->enumerateProtocols( i ) ; ++i )
318  d->backendFactory->setProtocolBackend( name, d->listView->chosenBackend( name ) );
319 }
320 
321 void Kleo::BackendConfigWidget::virtual_hook( int, void* ) {}
322 
323 #include "backendconfigwidget.moc"
Simple KDialogBase wrapper around CryptoConfigModule.