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 "directoryserviceswidget.h"
00034
00035 #include "ui_directoryserviceswidget.h"
00036
00037 #include <KIcon>
00038 #include <KDebug>
00039
00040 #include <QItemDelegate>
00041 #include <QAbstractTableModel>
00042 #include <QSpinBox>
00043 #include <QComboBox>
00044 #include <QHeaderView>
00045 #include <QMenu>
00046 #include <QAction>
00047
00048 #include <boost/bind.hpp>
00049
00050 #include <vector>
00051
00052 #include <climits>
00053 #include <cassert>
00054 #include <algorithm>
00055
00056 using namespace Kleo;
00057 using namespace boost;
00058
00059 namespace {
00060
00061 static KUrl defaultX509Service() {
00062 KUrl url;
00063 url.setProtocol( "ldap" );
00064 url.setHost( i18nc("default server name, keep it a valid domain name, ie. no spaces", "server") );
00065 return url;
00066 }
00067 static KUrl defaultOpenPGPService() {
00068 KUrl url;
00069 url.setProtocol( "hkp" );
00070 url.setHost( "keys.gnupg.net" );
00071 return url;
00072 }
00073
00074 static bool is_ldap_scheme( const KUrl & url ) {
00075 const QString scheme = url.protocol();
00076 return QString::compare( scheme, QLatin1String( "ldap" ), Qt::CaseInsensitive ) == 0
00077 || QString::compare( scheme, QLatin1String( "ldaps" ), Qt::CaseInsensitive ) == 0;
00078 }
00079
00080 static const struct {
00081 const char label[6];
00082 unsigned short port;
00083 DirectoryServicesWidget::Scheme base;
00084 } protocols[] = {
00085 { I18N_NOOP("hkp"), 11371, DirectoryServicesWidget::HKP },
00086 { I18N_NOOP("http"), 80, DirectoryServicesWidget::HTTP },
00087 { I18N_NOOP("https"), 443, DirectoryServicesWidget::HTTP },
00088 { I18N_NOOP("ftp"), 21, DirectoryServicesWidget::FTP },
00089 { I18N_NOOP("ftps"), 990, DirectoryServicesWidget::FTP },
00090 { I18N_NOOP("ldap"), 389, DirectoryServicesWidget::LDAP },
00091 { I18N_NOOP("ldaps"), 636, DirectoryServicesWidget::LDAP },
00092 };
00093 static const unsigned int numProtocols = sizeof protocols / sizeof *protocols;
00094
00095 static unsigned short default_port( const QString & scheme ) {
00096 for ( unsigned int i = 0 ; i < numProtocols ; ++i )
00097 if ( QString::compare( scheme, QLatin1String( protocols[i].label ), Qt::CaseInsensitive ) == 0 )
00098 return protocols[i].port;
00099 return 0;
00100 }
00101
00102 static QString display_scheme( const KUrl & url ) {
00103 if ( url.scheme().isEmpty() )
00104 return QLatin1String( "hkp" );
00105 else
00106 return url.scheme();
00107 }
00108
00109 static QString display_host( const KUrl & url ) {
00110
00111 if ( url.host().isEmpty() )
00112 return url.path();
00113 else
00114 return url.host();
00115 }
00116
00117 static unsigned short display_port( const KUrl & url ) {
00118 if ( url.port() > 0 )
00119 return url.port();
00120 else
00121 return default_port( display_scheme( url ) );
00122 }
00123
00124 static bool is_default_port( const KUrl & url ) {
00125 return display_port( url ) == default_port( display_scheme( url ) ) ;
00126 }
00127
00128 static QRect calculate_geometry( const QRect & cell, const QSize & sizeHint ) {
00129 const int height = qMax( cell.height(), sizeHint.height() );
00130 return QRect( cell.left(), cell.top() - ( height - cell.height() ) / 2,
00131 cell.width(), height );
00132 }
00133
00134 struct KUrl_compare : std::binary_function<KUrl,KUrl,bool> {
00135 bool operator()( const KUrl & lhs, const KUrl & rhs ) const {
00136 return QString::compare( display_scheme( lhs ), display_scheme( rhs ), Qt::CaseInsensitive ) == 0
00137 && QString::compare( display_host( lhs ), display_host( rhs ), Qt::CaseInsensitive ) == 0
00138 && lhs.port() == rhs.port()
00139 && lhs.user() == rhs.user()
00140
00141 && ( !is_ldap_scheme( lhs )
00142 || KUrl::fromPercentEncoding( lhs.query().mid( 1 ).toLatin1() )
00143 == KUrl::fromPercentEncoding( rhs.query().mid( 1 ).toLatin1() ) ) ;
00144 }
00145 };
00146
00147 class Model : public QAbstractTableModel {
00148 Q_OBJECT
00149 public:
00150 explicit Model( QObject * parent=0 )
00151 : QAbstractTableModel( parent ),
00152 m_items(),
00153 m_openPGPReadOnly( false ),
00154 m_x509ReadOnly( false ),
00155 m_schemes( DirectoryServicesWidget::AllSchemes )
00156 {
00157
00158 }
00159
00160 void setOpenPGPReadOnly( bool ro ) {
00161 if ( ro == m_openPGPReadOnly )
00162 return;
00163 m_openPGPReadOnly = ro;
00164 for ( unsigned int row = 0, end = rowCount() ; row != end ; ++row )
00165 if ( isOpenPGPService( row ) )
00166 emit dataChanged( index( row, 0 ), index( row, NumColumns ) );
00167 }
00168
00169 void setX509ReadOnly( bool ro ) {
00170 if ( ro == m_x509ReadOnly )
00171 return;
00172 m_x509ReadOnly = ro;
00173 for ( unsigned int row = 0, end = rowCount() ; row != end ; ++row )
00174 if ( isX509Service( row ) )
00175 emit dataChanged( index( row, 0 ), index( row, NumColumns ) );
00176 }
00177
00178 QModelIndex addOpenPGPService( const KUrl & url, bool force=false ) {
00179 return addService( url, false, true, force );
00180 }
00181 QModelIndex addX509Service( const KUrl & url, bool force=false ) {
00182 return addService( url, true, false, force );
00183 }
00184 QModelIndex addService( const KUrl & url, bool x509, bool pgp, bool force ) {
00185 const std::vector<Item>::iterator it = force ? m_items.end() : findExistingUrl( url ) ;
00186 unsigned int row;
00187 if ( it != m_items.end() ) {
00188
00189 it->x509 |= x509;
00190 it->pgp |= pgp;
00191 row = it - m_items.begin() ;
00192 emit dataChanged( index( row, std::min( X509, OpenPGP ) ), index( row, std::max( X509, OpenPGP ) ) );
00193 } else {
00194
00195 const Item item = { url, x509, pgp };
00196 row = m_items.size();
00197 beginInsertRows( QModelIndex(), row, row );
00198 m_items.push_back( item );
00199 endInsertRows();
00200 }
00201 return index( row, firstEditableColumn( row ) );
00202 }
00203
00204 unsigned int numServices() const { return m_items.size(); }
00205 bool isOpenPGPService( unsigned int row ) const { return row < m_items.size() && m_items[row].pgp; }
00206 bool isX509Service( unsigned int row ) const { return row < m_items.size() && m_items[row].x509 && isLdapRow( row ) ; }
00207 KUrl service( unsigned int row ) const { return row < m_items.size() ? m_items[row].url : KUrl() ; }
00208
00209 bool isReadOnlyRow( unsigned int row ) const {
00210 return ( isX509Service( row ) && m_x509ReadOnly )
00211 || ( isOpenPGPService( row ) && m_openPGPReadOnly );
00212 }
00213
00214 enum Columns {
00215 Scheme,
00216 Host,
00217 Port,
00218 BaseDN,
00219 UserName,
00220 Password,
00221 X509,
00222 OpenPGP,
00223
00224 NumColumns
00225 };
00226
00227 QModelIndex duplicateRow( unsigned int row ) {
00228 if ( row >= m_items.size() )
00229 return QModelIndex();
00230
00231 beginInsertRows( QModelIndex(), row+1, row+1 );
00232 m_items.insert( m_items.begin() + row + 1, m_items[row] );
00233 if ( m_items[row].pgp )
00234 m_items[row+1].pgp = false;
00235 endInsertRows();
00236 return index( row+1, 0 );
00237 }
00238
00239 void deleteRow( unsigned int row ) {
00240 if ( row >= m_items.size() )
00241 return;
00242
00243 beginRemoveRows( QModelIndex(), row, row );
00244 m_items.erase( m_items.begin() + row );
00245 endInsertRows();
00246 }
00247
00248 void clear() {
00249 if ( m_items.empty() )
00250 return;
00251 beginRemoveRows( QModelIndex(), 0, m_items.size()-1 );
00252 m_items.clear();
00253 endRemoveRows();
00254 }
00255
00256 int columnCount( const QModelIndex & =QModelIndex() ) const { return NumColumns; }
00257 int rowCount( const QModelIndex & =QModelIndex() ) const { return m_items.size(); }
00258
00259 QVariant data( const QModelIndex & idx, int role ) const;
00260 QVariant headerData( int section, Qt::Orientation o, int role ) const;
00261
00262 Qt::ItemFlags flags( const QModelIndex & idx ) const;
00263 bool setData( const QModelIndex & idx, const QVariant & value, int role );
00264
00265 private:
00266 bool doSetData( unsigned int row, unsigned int column, const QVariant & value, int role );
00267 void setExclusivePgpFlag( unsigned int row );
00268
00269 static QString toolTipForColumn( int column );
00270 bool isLdapRow( unsigned int row ) const;
00271 int firstEditableColumn( unsigned int ) const {
00272 return Host;
00273 }
00274
00275 private:
00276 struct Item {
00277 KUrl url;
00278 bool x509 : 1;
00279 bool pgp : 1;
00280 };
00281 std::vector<Item> m_items;
00282 bool m_openPGPReadOnly : 1;
00283 bool m_x509ReadOnly : 1;
00284 DirectoryServicesWidget::Schemes m_schemes;
00285
00286 private:
00287 std::vector<Item>::iterator findExistingUrl( const KUrl & url ) {
00288 return std::find_if( m_items.begin(), m_items.end(),
00289 bind( KUrl_compare(), url, bind( &Item::url, _1 ) ) );
00290 }
00291 };
00292
00293 class Delegate : public QItemDelegate {
00294 Q_OBJECT
00295 public:
00296 explicit Delegate( QObject * parent=0 )
00297 : QItemDelegate( parent ),
00298 m_schemes( DirectoryServicesWidget::AllSchemes )
00299 {
00300
00301 }
00302
00303 void setAllowedSchemes( const DirectoryServicesWidget::Schemes schemes ) {
00304 m_schemes = schemes;
00305 };
00306 DirectoryServicesWidget::Schemes allowedSchemes() const { return m_schemes; }
00307
00308
00309 QWidget * createEditor( QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & idx ) const {
00310 switch ( idx.column() ) {
00311 case Model::Scheme:
00312 return createSchemeWidget( parent );
00313 case Model::Port:
00314 return createPortWidget( parent );
00315 }
00316 return QItemDelegate::createEditor( parent, option, idx );
00317 }
00318
00319
00320 void setEditorData( QWidget * editor, const QModelIndex & idx ) const {
00321 switch ( idx.column() ) {
00322 case Model::Scheme:
00323 setSchemeEditorData( qobject_cast<QComboBox*>( editor ), idx.data( Qt::EditRole ).toString() );
00324 break;
00325 case Model::Port:
00326 setPortEditorData( qobject_cast<QSpinBox*>( editor ), idx.data( Qt::EditRole ).toInt() );
00327 break;
00328 default:
00329 QItemDelegate::setEditorData( editor, idx );
00330 break;
00331 }
00332 }
00333
00334
00335 void setModelData( QWidget * editor, QAbstractItemModel * model, const QModelIndex & idx ) const {
00336 switch ( idx.column() ) {
00337 case Model::Scheme:
00338 setSchemeModelData( qobject_cast<QComboBox*>( editor ), model, idx );
00339 break;
00340 case Model::Port:
00341 setPortModelData( qobject_cast<QSpinBox*>( editor ), model, idx );
00342 break;
00343 default:
00344 QItemDelegate::setModelData( editor, model, idx );
00345 break;
00346 }
00347 }
00348
00349
00350 void updateEditorGeometry( QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
00351 if ( index.column() == Model::Scheme || index.column() == Model::Port )
00352 editor->setGeometry( calculate_geometry( option.rect, editor->sizeHint() ) );
00353 else
00354 QItemDelegate::updateEditorGeometry( editor, option, index );
00355 }
00356
00357 private:
00358 QWidget * createSchemeWidget( QWidget * parent ) const {
00359 if ( !m_schemes )
00360 return 0;
00361 QComboBox * cb = new QComboBox( parent );
00362 for ( unsigned int i = 0 ; i < numProtocols ; ++i )
00363 if ( m_schemes & protocols[i].base )
00364 cb->addItem( i18n( protocols[i].label ), protocols[i].label );
00365 assert( cb->count() > 0 );
00366 return cb;
00367 }
00368 void setSchemeEditorData( QComboBox * cb, const QString & scheme ) const {
00369 assert( cb );
00370 cb->setCurrentIndex( cb->findData( scheme, Qt::UserRole, Qt::MatchFixedString ) );
00371 }
00372 void setSchemeModelData( const QComboBox * cb, QAbstractItemModel * model, const QModelIndex & idx ) const {
00373 assert( cb );
00374 assert( model );
00375 model->setData( idx, cb->itemData( cb->currentIndex() ) );
00376 }
00377
00378 QWidget * createPortWidget( QWidget * parent ) const {
00379 QSpinBox * sb = new QSpinBox( parent );
00380 sb->setRange( 1, USHRT_MAX );
00381 return sb;
00382 }
00383 void setPortEditorData( QSpinBox * sb, unsigned short port ) const {
00384 assert( sb );
00385 sb->setValue( port );
00386 }
00387 void setPortModelData( const QSpinBox * sb, QAbstractItemModel * model, const QModelIndex & idx ) const {
00388 assert( sb );
00389 assert( model );
00390 model->setData( idx, sb->value() );
00391 }
00392
00393 private:
00394 DirectoryServicesWidget::Schemes m_schemes;
00395 };
00396
00397 }
00398
00399 class DirectoryServicesWidget::Private {
00400 friend class ::Kleo::DirectoryServicesWidget;
00401 DirectoryServicesWidget * const q;
00402 public:
00403 explicit Private( DirectoryServicesWidget * qq )
00404 : q( qq ),
00405 protocols( AllProtocols ),
00406 readOnlyProtocols( NoProtocol ),
00407 model(),
00408 delegate(),
00409 ui( q )
00410 {
00411 ui.treeView->setModel( &model );
00412 ui.treeView->setItemDelegate( &delegate );
00413
00414 connect( &model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
00415 q, SIGNAL(changed()) );
00416 connect( &model, SIGNAL(rowsInserted(QModelIndex,int,int)),
00417 q, SIGNAL(changed()) );
00418 connect( &model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
00419 q, SIGNAL(changed()) );
00420 connect( ui.treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
00421 q, SLOT(slotSelectionChanged()) );
00422
00423 slotShowUserAndPasswordToggled( false );
00424 }
00425
00426 private:
00427 void slotNewClicked() {
00428 int row = selectedRow();
00429 if ( row < 0 )
00430 row = currentRow();
00431 if ( row < 0 || model.isReadOnlyRow( row ) )
00432 if ( protocols & OpenPGPProtocol )
00433 slotNewOpenPGPClicked();
00434 else if ( protocols & X509Protocol )
00435 slotNewX509Clicked();
00436 else
00437 assert( !"This should not happen.");
00438 else
00439 edit( model.duplicateRow( row ) );
00440 }
00441 void edit( const QModelIndex & index ) {
00442 if ( index.isValid() ) {
00443 ui.treeView->clearSelection();
00444 ui.treeView->selectionModel()->setCurrentIndex( index, QItemSelectionModel::Select|QItemSelectionModel::Rows );
00445 ui.treeView->edit( index );
00446 }
00447 }
00448 void slotNewX509Clicked() {
00449 edit( model.addX509Service( defaultX509Service(), true ) );
00450 }
00451 void slotNewOpenPGPClicked() {
00452 edit( model.addOpenPGPService( defaultOpenPGPService(), true ) );
00453 }
00454 void slotDeleteClicked() {
00455 model.deleteRow( selectedRow() );
00456 }
00457 void slotSelectionChanged() {
00458 enableDisableActions();
00459 }
00460 void slotShowUserAndPasswordToggled( bool on ) {
00461 QHeaderView * const hv = ui.treeView->header();
00462 assert( hv );
00463 hv->setSectionHidden( Model::UserName, !on );
00464 hv->setSectionHidden( Model::Password, !on );
00465 }
00466
00467 int selectedRow() const {
00468 const QModelIndexList mil = ui.treeView->selectionModel()->selectedRows();
00469 return mil.empty() ? -1 : mil.front().row();
00470 }
00471 int currentRow() const {
00472 const QModelIndex idx = ui.treeView->selectionModel()->currentIndex();
00473 return idx.isValid() ? idx.row() : -1 ;
00474 }
00475
00476 void showHideColumns();
00477
00478 void enableDisableActions() {
00479 const bool x509 = ( protocols & X509Protocol ) && !( readOnlyProtocols & X509Protocol ) ;
00480 const bool pgp = ( protocols & OpenPGPProtocol ) && !( readOnlyProtocols & OpenPGPProtocol ) ;
00481 ui.newX509Action.setEnabled( x509 );
00482 ui.newOpenPGPAction.setEnabled( pgp );
00483 if ( x509 && pgp ) {
00484 ui.newTB->setMenu( &ui.newMenu );
00485 ui.newTB->setPopupMode( QToolButton::MenuButtonPopup );
00486 } else {
00487 ui.newTB->setMenu( 0 );
00488 ui.newTB->setPopupMode( QToolButton::DelayedPopup );
00489 ui.newTB->setEnabled( x509 || pgp );
00490 }
00491 const int row = selectedRow();
00492 ui.deleteTB->setEnabled( row >= 0 && !model.isReadOnlyRow( row ) );
00493 }
00494
00495 private:
00496 Protocols protocols;
00497 Protocols readOnlyProtocols;
00498 Model model;
00499 Delegate delegate;
00500 struct UI : Ui_DirectoryServicesWidget {
00501 QAction newX509Action;
00502 QAction newOpenPGPAction;
00503 QMenu newMenu;
00504
00505 explicit UI( DirectoryServicesWidget * q )
00506 : Ui_DirectoryServicesWidget(),
00507 newX509Action( i18nc("New X.509 Directory Server", "X.509"), q ),
00508 newOpenPGPAction( i18nc("New OpenPGP Directory Server", "OpenPGP"), q ),
00509 newMenu( q )
00510 {
00511 newX509Action.setObjectName( "newX509Action" );
00512 newOpenPGPAction.setObjectName( "newOpenPGPAction" );
00513 newMenu.setObjectName( "newMenu" );
00514
00515 setupUi( q );
00516
00517 connect( &newX509Action, SIGNAL(triggered()), q, SLOT(slotNewX509Clicked()) );
00518 connect( &newOpenPGPAction, SIGNAL(triggered()), q, SLOT(slotNewOpenPGPClicked()) );
00519
00520 newMenu.addAction( &newX509Action );
00521 newMenu.addAction( &newOpenPGPAction );
00522
00523 newTB->setMenu( &newMenu );
00524 }
00525
00526 } ui;
00527 };
00528
00529 DirectoryServicesWidget::DirectoryServicesWidget( QWidget * p, Qt::WindowFlags f )
00530 : QWidget( p, f ), d( new Private( this ) )
00531 {
00532
00533 }
00534
00535
00536 DirectoryServicesWidget::~DirectoryServicesWidget() {
00537 delete d;
00538 }
00539
00540 void DirectoryServicesWidget::setAllowedSchemes( Schemes schemes ) {
00541 d->delegate.setAllowedSchemes( schemes );
00542 d->showHideColumns();
00543 }
00544
00545 DirectoryServicesWidget::Schemes DirectoryServicesWidget::allowedSchemes() const {
00546 return d->delegate.allowedSchemes();
00547 }
00548
00549 void DirectoryServicesWidget::setAllowedProtocols( Protocols protocols ) {
00550 if ( d->protocols == protocols )
00551 return;
00552 d->protocols = protocols;
00553 d->showHideColumns();
00554 d->enableDisableActions();
00555 }
00556
00557 DirectoryServicesWidget::Protocols DirectoryServicesWidget::allowedProtocols() const {
00558 return d->protocols;
00559 }
00560
00561 void DirectoryServicesWidget::setReadOnlyProtocols( Protocols protocols ) {
00562 if ( d->readOnlyProtocols == protocols )
00563 return;
00564 d->readOnlyProtocols = protocols;
00565 d->model.setOpenPGPReadOnly( protocols & OpenPGPProtocol );
00566 d->model.setX509ReadOnly( protocols & X509Protocol );
00567 d->enableDisableActions();
00568 }
00569
00570 DirectoryServicesWidget::Protocols DirectoryServicesWidget::readOnlyProtocols() const {
00571 return d->readOnlyProtocols;
00572 }
00573
00574 void DirectoryServicesWidget::addOpenPGPServices( const KUrl::List & urls ) {
00575 Q_FOREACH( const KUrl & url, urls )
00576 d->model.addOpenPGPService( url );
00577 }
00578
00579 KUrl::List DirectoryServicesWidget::openPGPServices() const {
00580 KUrl::List result;
00581 for ( unsigned int i = 0, end = d->model.numServices() ; i != end ; ++i )
00582 if ( d->model.isOpenPGPService( i ) )
00583 result.push_back( d->model.service( i ) );
00584 return result;
00585 }
00586
00587 void DirectoryServicesWidget::addX509Services( const KUrl::List & urls ) {
00588 Q_FOREACH( const KUrl & url, urls )
00589 d->model.addX509Service( url );
00590 }
00591
00592 KUrl::List DirectoryServicesWidget::x509Services() const {
00593 KUrl::List result;
00594 for ( unsigned int i = 0, end = d->model.numServices() ; i != end ; ++i )
00595 if ( d->model.isX509Service( i ) )
00596 result.push_back( d->model.service( i ) );
00597 return result;
00598 }
00599
00600 void DirectoryServicesWidget::clear() {
00601 if ( !d->model.numServices() )
00602 return;
00603 d->model.clear();
00604 emit changed();
00605 }
00606
00607 void DirectoryServicesWidget::Private::showHideColumns() {
00608 QHeaderView * const hv = ui.treeView->header();
00609 assert( hv );
00610
00611 hv->setSectionHidden( Model::Scheme, protocols == X509Protocol );
00612
00613 hv->setSectionHidden( Model::X509, protocols != AllProtocols );
00614 hv->setSectionHidden( Model::OpenPGP, protocols != AllProtocols );
00615 }
00616
00617
00618
00619
00620
00621 QVariant Model::headerData( int section, Qt::Orientation orientation, int role ) const {
00622 if ( orientation == Qt::Horizontal )
00623 if ( role == Qt::ToolTipRole )
00624 return toolTipForColumn( section );
00625 else if ( role == Qt::DisplayRole )
00626 switch ( section ) {
00627 case Scheme: return i18n("Scheme");
00628 case Host: return i18n("Server Name");
00629 case Port: return i18n("Server Port");
00630 case BaseDN: return i18n("Base DN");
00631 case UserName: return i18n("User Name");
00632 case Password: return i18n("Password");
00633 case X509: return i18n("X.509");
00634 case OpenPGP: return i18n("OpenPGP");
00635 default: return QVariant();
00636 }
00637 else
00638 return QVariant();
00639 else
00640 return QAbstractTableModel::headerData( section, orientation, role );
00641 }
00642
00643 QVariant Model::data( const QModelIndex & index, int role ) const {
00644 const unsigned int row = index.row();
00645 if ( index.isValid() && row < m_items.size() )
00646 switch ( role ) {
00647 case Qt::ToolTipRole: {
00648 const QString tt = toolTipForColumn( index.column() );
00649 if ( !isReadOnlyRow( index.row() ) )
00650 return tt;
00651 else
00652 return tt.isEmpty()
00653 ? i18n("(read-only)")
00654 : i18nc("amended tooltip; %1: original tooltip",
00655 "%1 (read-only)", tt );
00656 }
00657 case Qt::DisplayRole:
00658 case Qt::EditRole:
00659 switch ( index.column() ) {
00660 case Scheme:
00661 return display_scheme( m_items[row].url );
00662 case Host:
00663 return display_host( m_items[row].url );
00664 case Port:
00665 return display_port( m_items[row].url );
00666 case BaseDN:
00667 if ( isLdapRow( row ) )
00668 return KUrl::fromPercentEncoding( m_items[row].url.query().mid( 1 ).toLatin1() );
00669 else
00670 return QVariant();
00671 case UserName:
00672 return m_items[row].url.user();
00673 case Password:
00674 return m_items[row].url.pass();
00675 case X509:
00676 case OpenPGP:
00677 default:
00678 return QVariant();
00679 }
00680 case Qt::CheckStateRole:
00681 switch ( index.column() ) {
00682 case X509:
00683 return m_items[row].x509 && isLdapRow( row ) ? Qt::Checked : Qt::Unchecked ;
00684 case OpenPGP:
00685 return m_items[row].pgp ? Qt::Checked : Qt::Unchecked ;
00686 default:
00687 return QVariant();
00688 }
00689 }
00690 return QVariant();
00691 }
00692
00693 bool Model::isLdapRow( unsigned int row ) const {
00694 if ( row >= m_items.size() )
00695 return false;
00696 return is_ldap_scheme( m_items[row].url );
00697 }
00698
00699 Qt::ItemFlags Model::flags( const QModelIndex & index ) const {
00700 const unsigned int row = index.row();
00701 Qt::ItemFlags flags = QAbstractTableModel::flags( index );
00702 if ( isReadOnlyRow( row ) )
00703 flags &= ~Qt::ItemIsSelectable ;
00704 if ( index.isValid() && row < m_items.size() )
00705 switch ( index.column() ) {
00706 case Scheme:
00707 switch ( m_schemes ) {
00708 default:
00709 if ( !isReadOnlyRow( row ) )
00710 return flags | Qt::ItemIsEditable ;
00711
00712 case DirectoryServicesWidget::HKP:
00713 case DirectoryServicesWidget::HTTP:
00714 case DirectoryServicesWidget::FTP:
00715 case DirectoryServicesWidget::LDAP:
00716
00717 return flags & ~(Qt::ItemIsEditable|Qt::ItemIsEnabled) ;
00718 }
00719 case Host:
00720 case Port:
00721 if ( isReadOnlyRow( row ) )
00722 return flags & ~(Qt::ItemIsEnabled|Qt::ItemIsEnabled) ;
00723 else
00724 return flags | Qt::ItemIsEditable ;
00725 case BaseDN:
00726 if ( isLdapRow( row ) && !isReadOnlyRow( row ) )
00727 return flags | Qt::ItemIsEditable ;
00728 else
00729 return flags & ~(Qt::ItemIsEditable|Qt::ItemIsEnabled) ;
00730 case UserName:
00731 case Password:
00732 if ( isReadOnlyRow( row ) )
00733 return flags & ~(Qt::ItemIsEditable|Qt::ItemIsEnabled) ;
00734 else
00735 return flags | Qt::ItemIsEditable ;
00736 case X509:
00737 if ( !isLdapRow( row ) )
00738 return flags & ~(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled) ;
00739
00740 case OpenPGP:
00741 if ( isReadOnlyRow( row ) )
00742 return flags & ~(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled) ;
00743 else
00744 return flags | Qt::ItemIsUserCheckable ;
00745 }
00746 return flags;
00747 }
00748
00749 bool Model::setData( const QModelIndex & idx, const QVariant & value, int role ) {
00750 const unsigned int row = idx.row();
00751 if ( !idx.isValid() || row >= m_items.size() )
00752 return false;
00753 if ( isReadOnlyRow( row ) )
00754 return false;
00755 if ( !doSetData( row, idx.column(), value, role ) )
00756 return false;
00757 emit dataChanged( idx, idx );
00758 return true;
00759 }
00760
00761 bool Model::doSetData( unsigned int row, unsigned int column, const QVariant & value, int role ) {
00762 if ( role == Qt::EditRole )
00763 switch ( column ) {
00764 case Scheme:
00765 if ( is_default_port( m_items[row].url ) ) {
00766
00767 m_items[row].url.setPort( -1 );
00768 const QModelIndex changed = index( row, Port );
00769 emit dataChanged( changed, changed );
00770 }
00771 m_items[row].url.setProtocol( value.toString() );
00772 return true;
00773 case Host:
00774 if ( display_host( m_items[row].url ) != m_items[row].url.host() ) {
00775 m_items[row].url.setProtocol( display_scheme( m_items[row].url ) );
00776 m_items[row].url.setPath( "/" );
00777 }
00778 m_items[row].url.setHost( value.toString() );
00779 return true;
00780 case Port:
00781 if ( value.toUInt() == default_port( display_scheme( m_items[row].url ) ) )
00782 m_items[row].url.setPort( -1 );
00783 else
00784 m_items[row].url.setPort( value.toUInt() );
00785 return true;
00786 case BaseDN:
00787 if ( value.toString().isEmpty() ) {
00788 m_items[row].url.setPath( QString() );
00789 m_items[row].url.setQuery( QString() );
00790 } else {
00791 m_items[row].url.setPath( "/" );
00792 m_items[row].url.setQuery( value.toString() );
00793 }
00794 return true;
00795 case UserName:
00796 m_items[row].url.setUser( value.toString() );
00797 return true;
00798 case Password:
00799 m_items[row].url.setPass( value.toString() );
00800 return true;
00801 }
00802 if ( role == Qt::CheckStateRole )
00803 switch ( column ) {
00804 case X509:
00805 m_items[row].x509 = value.toInt() == Qt::Checked ;
00806 return true;
00807 case OpenPGP:
00808 {
00809 const bool on = value.toInt() == Qt::Checked ;
00810 if ( on )
00811 setExclusivePgpFlag( row );
00812 else
00813 m_items[row].pgp = false;
00814 }
00815 return true;
00816 }
00817 return false;
00818 }
00819
00820 void Model::setExclusivePgpFlag( unsigned int row ) {
00821 if ( row >= m_items.size() || m_items[row].pgp )
00822 return;
00823 m_items[row].pgp = true;
00824 for ( unsigned int i = 0, end = m_items.size() ; i < end ; ++i )
00825 if ( i != row )
00826 if ( m_items[i].pgp ) {
00827 m_items[i].pgp = false;
00828 const QModelIndex changed = index( i, OpenPGP );
00829 emit dataChanged( changed, changed );
00830 break;
00831 }
00832 }
00833
00834
00835 QString Model::toolTipForColumn( int column ) {
00836 switch ( column ) {
00837 case Scheme: return i18n("Select the access protocol (scheme) that the "
00838 "directory service is available through.");
00839 case Host: return i18n("Enter the name or IP address of the server "
00840 "hosting the directory service.");
00841 case Port: return i18n("<b>(Optional, the default is fine in most cases)</b> "
00842 "Pick the port number the directory service is "
00843 "listening on.");
00844 case BaseDN: return i18n("<b>(Only for LDAP)</b> "
00845 "Enter the base DN for this LDAP server to "
00846 "limit searches to only that subtree of the directory.");
00847 case UserName: return i18n("<b>(Optional)</b> "
00848 "Enter your user name here, if needed.");
00849 case Password: return i18n("<b>(Optional, not recommended)</b> "
00850 "Enter your password here, if needed. "
00851 "Note that the password will be saved in the clear "
00852 "in a config file in your home directory.");
00853 case X509: return i18n("Check this column if this directory service is "
00854 "providing S/MIME (X.509) certificates.");
00855 case OpenPGP: return i18n("Check this column if this directory service is "
00856 "providing OpenPGP certificates.");
00857 default:
00858 return QString();
00859 }
00860 }
00861
00862 #include "directoryserviceswidget.moc"
00863 #include "moc_directoryserviceswidget.cpp"