• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

libkleo

directoryserviceswidget.cpp

Go to the documentation of this file.
00001 /*
00002     directoryserviceswidget.cpp
00003 
00004     This file is part of Kleopatra, the KDE keymanager
00005     Copyright (c) 2001,2002,2004 Klar�vdalens Datakonsult AB
00006 
00007     Kleopatra is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     Kleopatra is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021     In addition, as a special exception, the copyright holders give
00022     permission to link the code of this program with any edition of
00023     the Qt library by Trolltech AS, Norway (or with modified versions
00024     of Qt that use the same license as Qt), and distribute linked
00025     combinations including the two.  You must obey the GNU General
00026     Public License in all respects for all of the code used other than
00027     Qt.  If you modify this file, you may extend this exception to
00028     your version of the file, but you are not obligated to do so.  If
00029     you do not wish to do so, delete this exception statement from
00030     your version.
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         // work around "subkeys.pgp.net" being interpreted as a path, not host
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                 // ... ignore password...
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                 // existing item:
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                 // append new item
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; // enforce pgp exclusivitiy
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         /* reimp */ int columnCount( const QModelIndex & =QModelIndex() ) const { return NumColumns; }
00257         /* reimp */ int rowCount( const QModelIndex & =QModelIndex() ) const { return m_items.size(); }
00258 
00259         /* reimp */ QVariant data( const QModelIndex & idx, int role ) const;
00260         /* reimp */ QVariant headerData( int section, Qt::Orientation o, int role ) const;
00261 
00262         /* reimp */ Qt::ItemFlags flags( const QModelIndex & idx ) const;
00263         /* reimp */ 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         /* reimp */
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         /* reimp */
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         /* reimp */
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         /* reimp */
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 ); // valid port numbers
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     // don't show 'scheme' column when only accepting X509Protocol (###?)
00611     hv->setSectionHidden( Model::Scheme,  protocols == X509Protocol );
00612     // hide the protocol selection columns for if only one protocol is allowed anyway:
00613     hv->setSectionHidden( Model::X509,    protocols != AllProtocols );
00614     hv->setSectionHidden( Model::OpenPGP, protocols != AllProtocols );
00615 }
00616 
00617 //
00618 // Model
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() );  // decode query and skip leading '?'
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                 // else fall through
00712             case DirectoryServicesWidget::HKP:
00713             case DirectoryServicesWidget::HTTP:
00714             case DirectoryServicesWidget::FTP:
00715             case DirectoryServicesWidget::LDAP:
00716                 // only one scheme allowed -> no editing possible
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             // fall through
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                 // drag the port along with scheme changes
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( "/" ); // workaround KUrl parsing bug
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; // dataChanged() for this one is supposed to be emitted by the caller
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 // static
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"

libkleo

Skip menu "libkleo"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members