2 directoryserviceswidget.cpp
4 This file is part of Kleopatra, the KDE keymanager
5 Copyright (c) 2001,2002,2004 Klar�vdalens Datakonsult AB
7 Kleopatra is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 Kleopatra is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 In addition, as a special exception, the copyright holders give
22 permission to link the code of this program with any edition of
23 the Qt library by Trolltech AS, Norway (or with modified versions
24 of Qt that use the same license as Qt), and distribute linked
25 combinations including the two. You must obey the GNU General
26 Public License in all respects for all of the code used other than
27 Qt. If you modify this file, you may extend this exception to
28 your version of the file, but you are not obligated to do so. If
29 you do not wish to do so, delete this exception statement from
33 #include "directoryserviceswidget.h"
35 #include "ui_directoryserviceswidget.h"
40 #include <QItemDelegate>
41 #include <QAbstractTableModel>
44 #include <QHeaderView>
48 #include <boost/bind.hpp>
57 using namespace boost
;
61 static KUrl
defaultX509Service() {
63 url
.setProtocol( "ldap" );
64 url
.setHost( i18nc("default server name, keep it a valid domain name, ie. no spaces", "server") );
67 static KUrl
defaultOpenPGPService() {
69 url
.setProtocol( "hkp" );
70 url
.setHost( "keys.gnupg.net" );
74 static bool is_ldap_scheme( const KUrl
& url
) {
75 const QString scheme
= url
.protocol();
76 return QString::compare( scheme
, QLatin1String( "ldap" ), Qt::CaseInsensitive
) == 0
77 || QString::compare( scheme
, QLatin1String( "ldaps" ), Qt::CaseInsensitive
) == 0;
83 DirectoryServicesWidget::Scheme base
;
85 { I18N_NOOP("hkp"), 11371, DirectoryServicesWidget::HKP
},
86 { I18N_NOOP("http"), 80, DirectoryServicesWidget::HTTP
},
87 { I18N_NOOP("https"), 443, DirectoryServicesWidget::HTTP
},
88 { I18N_NOOP("ftp"), 21, DirectoryServicesWidget::FTP
},
89 { I18N_NOOP("ftps"), 990, DirectoryServicesWidget::FTP
},
90 { I18N_NOOP("ldap"), 389, DirectoryServicesWidget::LDAP
},
91 { I18N_NOOP("ldaps"), 636, DirectoryServicesWidget::LDAP
},
93 static const unsigned int numProtocols
= sizeof protocols
/ sizeof *protocols
;
95 static unsigned short default_port( const QString
& scheme
) {
96 for ( unsigned int i
= 0 ; i
< numProtocols
; ++i
)
97 if ( QString::compare( scheme
, QLatin1String( protocols
[i
].label
), Qt::CaseInsensitive
) == 0 )
98 return protocols
[i
].port
;
102 static QString
display_scheme( const KUrl
& url
) {
103 if ( url
.scheme().isEmpty() )
104 return QLatin1String( "hkp" );
109 static QString
display_host( const KUrl
& url
) {
110 // work around "subkeys.pgp.net" being interpreted as a path, not host
111 if ( url
.host().isEmpty() )
117 static unsigned short display_port( const KUrl
& url
) {
118 if ( url
.port() > 0 )
121 return default_port( display_scheme( url
) );
124 static bool is_default_port( const KUrl
& url
) {
125 return display_port( url
) == default_port( display_scheme( url
) ) ;
128 static QRect
calculate_geometry( const QRect
& cell
, const QSize
& sizeHint
) {
129 const int height
= qMax( cell
.height(), sizeHint
.height() );
130 return QRect( cell
.left(), cell
.top() - ( height
- cell
.height() ) / 2,
131 cell
.width(), height
);
134 struct KUrl_compare
: std::binary_function
<KUrl
,KUrl
,bool> {
135 bool operator()( const KUrl
& lhs
, const KUrl
& rhs
) const {
136 return QString::compare( display_scheme( lhs
), display_scheme( rhs
), Qt::CaseInsensitive
) == 0
137 && QString::compare( display_host( lhs
), display_host( rhs
), Qt::CaseInsensitive
) == 0
138 && lhs
.port() == rhs
.port()
139 && lhs
.user() == rhs
.user()
140 // ... ignore password...
141 && ( !is_ldap_scheme( lhs
)
142 || KUrl::fromPercentEncoding( lhs
.query().mid( 1 ).toLatin1() )
143 == KUrl::fromPercentEncoding( rhs
.query().mid( 1 ).toLatin1() ) ) ;
147 class Model
: public QAbstractTableModel
{
150 explicit Model( QObject
* parent
=0 )
151 : QAbstractTableModel( parent
),
153 m_openPGPReadOnly( false ),
154 m_x509ReadOnly( false ),
155 m_schemes( DirectoryServicesWidget::AllSchemes
)
160 void setOpenPGPReadOnly( bool ro
) {
161 if ( ro
== m_openPGPReadOnly
)
163 m_openPGPReadOnly
= ro
;
164 for ( unsigned int row
= 0, end
= rowCount() ; row
!= end
; ++row
)
165 if ( isOpenPGPService( row
) )
166 emit
dataChanged( index( row
, 0 ), index( row
, NumColumns
) );
169 void setX509ReadOnly( bool ro
) {
170 if ( ro
== m_x509ReadOnly
)
173 for ( unsigned int row
= 0, end
= rowCount() ; row
!= end
; ++row
)
174 if ( isX509Service( row
) )
175 emit
dataChanged( index( row
, 0 ), index( row
, NumColumns
) );
178 QModelIndex
addOpenPGPService( const KUrl
& url
, bool force
=false ) {
179 return addService( url
, false, true, force
);
181 QModelIndex
addX509Service( const KUrl
& url
, bool force
=false ) {
182 return addService( url
, true, false, force
);
184 QModelIndex
addService( const KUrl
& url
, bool x509
, bool pgp
, bool force
) {
185 const std::vector
<Item
>::iterator it
= force
? m_items
.end() : findExistingUrl( url
) ;
187 if ( it
!= m_items
.end() ) {
191 row
= it
- m_items
.begin() ;
192 emit
dataChanged( index( row
, std::min( X509
, OpenPGP
) ), index( row
, std::max( X509
, OpenPGP
) ) );
195 const Item item
= { url
, x509
, pgp
};
196 row
= m_items
.size();
197 beginInsertRows( QModelIndex(), row
, row
);
198 m_items
.push_back( item
);
201 return index( row
, firstEditableColumn( row
) );
204 unsigned int numServices() const { return m_items
.size(); }
205 bool isOpenPGPService( unsigned int row
) const { return row
< m_items
.size() && m_items
[row
].pgp
; }
206 bool isX509Service( unsigned int row
) const { return row
< m_items
.size() && m_items
[row
].x509
&& isLdapRow( row
) ; }
207 KUrl
service( unsigned int row
) const { return row
< m_items
.size() ? m_items
[row
].url
: KUrl() ; }
209 bool isReadOnlyRow( unsigned int row
) const {
210 return ( isX509Service( row
) && m_x509ReadOnly
)
211 || ( isOpenPGPService( row
) && m_openPGPReadOnly
);
227 QModelIndex
duplicateRow( unsigned int row
) {
228 if ( row
>= m_items
.size() )
229 return QModelIndex();
231 beginInsertRows( QModelIndex(), row
+1, row
+1 );
232 m_items
.insert( m_items
.begin() + row
+ 1, m_items
[row
] );
233 if ( m_items
[row
].pgp
)
234 m_items
[row
+1].pgp
= false; // enforce pgp exclusivitiy
236 return index( row
+1, 0 );
239 void deleteRow( unsigned int row
) {
240 if ( row
>= m_items
.size() )
243 beginRemoveRows( QModelIndex(), row
, row
);
244 m_items
.erase( m_items
.begin() + row
);
249 if ( m_items
.empty() )
251 beginRemoveRows( QModelIndex(), 0, m_items
.size()-1 );
256 /* reimp */ int columnCount( const QModelIndex
& =QModelIndex() ) const { return NumColumns
; }
257 /* reimp */ int rowCount( const QModelIndex
& =QModelIndex() ) const { return m_items
.size(); }
259 /* reimp */ QVariant
data( const QModelIndex
& idx
, int role
) const;
260 /* reimp */ QVariant
headerData( int section
, Qt::Orientation o
, int role
) const;
262 /* reimp */ Qt::ItemFlags
flags( const QModelIndex
& idx
) const;
263 /* reimp */ bool setData( const QModelIndex
& idx
, const QVariant
& value
, int role
);
266 bool doSetData( unsigned int row
, unsigned int column
, const QVariant
& value
, int role
);
267 void setExclusivePgpFlag( unsigned int row
);
269 static QString
toolTipForColumn( int column
);
270 bool isLdapRow( unsigned int row
) const;
271 int firstEditableColumn( unsigned int ) const {
281 std::vector
<Item
> m_items
;
282 bool m_openPGPReadOnly
: 1;
283 bool m_x509ReadOnly
: 1;
284 DirectoryServicesWidget::Schemes m_schemes
;
287 std::vector
<Item
>::iterator
findExistingUrl( const KUrl
& url
) {
288 return std::find_if( m_items
.begin(), m_items
.end(),
289 bind( KUrl_compare(), url
, bind( &Item::url
, _1
) ) );
293 class Delegate
: public QItemDelegate
{
296 explicit Delegate( QObject
* parent
=0 )
297 : QItemDelegate( parent
),
298 m_schemes( DirectoryServicesWidget::AllSchemes
)
303 void setAllowedSchemes( const DirectoryServicesWidget::Schemes schemes
) {
306 DirectoryServicesWidget::Schemes
allowedSchemes() const { return m_schemes
; }
309 QWidget
* createEditor( QWidget
* parent
, const QStyleOptionViewItem
& option
, const QModelIndex
& idx
) const {
310 switch ( idx
.column() ) {
312 return createSchemeWidget( parent
);
314 return createPortWidget( parent
);
316 return QItemDelegate::createEditor( parent
, option
, idx
);
320 void setEditorData( QWidget
* editor
, const QModelIndex
& idx
) const {
321 switch ( idx
.column() ) {
323 setSchemeEditorData( qobject_cast
<QComboBox
*>( editor
), idx
.data( Qt::EditRole
).toString() );
326 setPortEditorData( qobject_cast
<QSpinBox
*>( editor
), idx
.data( Qt::EditRole
).toInt() );
329 QItemDelegate::setEditorData( editor
, idx
);
335 void setModelData( QWidget
* editor
, QAbstractItemModel
* model
, const QModelIndex
& idx
) const {
336 switch ( idx
.column() ) {
338 setSchemeModelData( qobject_cast
<QComboBox
*>( editor
), model
, idx
);
341 setPortModelData( qobject_cast
<QSpinBox
*>( editor
), model
, idx
);
344 QItemDelegate::setModelData( editor
, model
, idx
);
350 void updateEditorGeometry( QWidget
* editor
, const QStyleOptionViewItem
& option
, const QModelIndex
& index
) const {
351 if ( index
.column() == Model::Scheme
|| index
.column() == Model::Port
)
352 editor
->setGeometry( calculate_geometry( option
.rect
, editor
->sizeHint() ) );
354 QItemDelegate::updateEditorGeometry( editor
, option
, index
);
358 QWidget
* createSchemeWidget( QWidget
* parent
) const {
361 QComboBox
* cb
= new QComboBox( parent
);
362 for ( unsigned int i
= 0 ; i
< numProtocols
; ++i
)
363 if ( m_schemes
& protocols
[i
].base
)
364 cb
->addItem( i18n( protocols
[i
].label
), protocols
[i
].label
);
365 assert( cb
->count() > 0 );
368 void setSchemeEditorData( QComboBox
* cb
, const QString
& scheme
) const {
370 cb
->setCurrentIndex( cb
->findData( scheme
, Qt::UserRole
, Qt::MatchFixedString
) );
372 void setSchemeModelData( const QComboBox
* cb
, QAbstractItemModel
* model
, const QModelIndex
& idx
) const {
375 model
->setData( idx
, cb
->itemData( cb
->currentIndex() ) );
378 QWidget
* createPortWidget( QWidget
* parent
) const {
379 QSpinBox
* sb
= new QSpinBox( parent
);
380 sb
->setRange( 1, USHRT_MAX
); // valid port numbers
383 void setPortEditorData( QSpinBox
* sb
, unsigned short port
) const {
385 sb
->setValue( port
);
387 void setPortModelData( const QSpinBox
* sb
, QAbstractItemModel
* model
, const QModelIndex
& idx
) const {
390 model
->setData( idx
, sb
->value() );
394 DirectoryServicesWidget::Schemes m_schemes
;
399 class DirectoryServicesWidget::Private
{
400 friend class ::Kleo::DirectoryServicesWidget
;
401 DirectoryServicesWidget
* const q
;
403 explicit Private( DirectoryServicesWidget
* qq
)
405 protocols( AllProtocols
),
406 readOnlyProtocols( NoProtocol
),
411 ui
.treeView
->setModel( &model
);
412 ui
.treeView
->setItemDelegate( &delegate
);
414 connect( &model
, SIGNAL(dataChanged(QModelIndex
,QModelIndex
)),
415 q
, SIGNAL(changed()) );
416 connect( &model
, SIGNAL(rowsInserted(QModelIndex
,int,int)),
417 q
, SIGNAL(changed()) );
418 connect( &model
, SIGNAL(rowsRemoved(QModelIndex
,int,int)),
419 q
, SIGNAL(changed()) );
420 connect( ui
.treeView
->selectionModel(), SIGNAL(selectionChanged(QItemSelection
,QItemSelection
)),
421 q
, SLOT(slotSelectionChanged()) );
423 slotShowUserAndPasswordToggled( false );
427 void slotNewClicked() {
428 int row
= selectedRow();
431 if ( row
< 0 || model
.isReadOnlyRow( row
) )
432 if ( protocols
& OpenPGPProtocol
)
433 slotNewOpenPGPClicked();
434 else if ( protocols
& X509Protocol
)
435 slotNewX509Clicked();
437 assert( !"This should not happen.");
439 edit( model
.duplicateRow( row
) );
441 void edit( const QModelIndex
& index
) {
442 if ( index
.isValid() ) {
443 ui
.treeView
->clearSelection();
444 ui
.treeView
->selectionModel()->setCurrentIndex( index
, QItemSelectionModel::Select
|QItemSelectionModel::Rows
);
445 ui
.treeView
->edit( index
);
448 void slotNewX509Clicked() {
449 edit( model
.addX509Service( defaultX509Service(), true ) );
451 void slotNewOpenPGPClicked() {
452 edit( model
.addOpenPGPService( defaultOpenPGPService(), true ) );
454 void slotDeleteClicked() {
455 model
.deleteRow( selectedRow() );
457 void slotSelectionChanged() {
458 enableDisableActions();
460 void slotShowUserAndPasswordToggled( bool on
) {
461 QHeaderView
* const hv
= ui
.treeView
->header();
463 hv
->setSectionHidden( Model::UserName
, !on
);
464 hv
->setSectionHidden( Model::Password
, !on
);
467 int selectedRow() const {
468 const QModelIndexList mil
= ui
.treeView
->selectionModel()->selectedRows();
469 return mil
.empty() ? -1 : mil
.front().row();
471 int currentRow() const {
472 const QModelIndex idx
= ui
.treeView
->selectionModel()->currentIndex();
473 return idx
.isValid() ? idx
.row() : -1 ;
476 void showHideColumns();
478 void enableDisableActions() {
479 const bool x509
= ( protocols
& X509Protocol
) && !( readOnlyProtocols
& X509Protocol
) ;
480 const bool pgp
= ( protocols
& OpenPGPProtocol
) && !( readOnlyProtocols
& OpenPGPProtocol
) ;
481 ui
.newX509Action
.setEnabled( x509
);
482 ui
.newOpenPGPAction
.setEnabled( pgp
);
484 ui
.newTB
->setMenu( &ui
.newMenu
);
485 ui
.newTB
->setPopupMode( QToolButton::MenuButtonPopup
);
487 ui
.newTB
->setMenu( 0 );
488 ui
.newTB
->setPopupMode( QToolButton::DelayedPopup
);
489 ui
.newTB
->setEnabled( x509
|| pgp
);
491 const int row
= selectedRow();
492 ui
.deleteTB
->setEnabled( row
>= 0 && !model
.isReadOnlyRow( row
) );
497 Protocols readOnlyProtocols
;
500 struct UI
: Ui_DirectoryServicesWidget
{
501 QAction newX509Action
;
502 QAction newOpenPGPAction
;
505 explicit UI( DirectoryServicesWidget
* q
)
506 : Ui_DirectoryServicesWidget(),
507 newX509Action( i18nc("New X.509 Directory Server", "X.509"), q
),
508 newOpenPGPAction( i18nc("New OpenPGP Directory Server", "OpenPGP"), q
),
511 newX509Action
.setObjectName( "newX509Action" );
512 newOpenPGPAction
.setObjectName( "newOpenPGPAction" );
513 newMenu
.setObjectName( "newMenu" );
517 connect( &newX509Action
, SIGNAL(triggered()), q
, SLOT(slotNewX509Clicked()) );
518 connect( &newOpenPGPAction
, SIGNAL(triggered()), q
, SLOT(slotNewOpenPGPClicked()) );
520 newMenu
.addAction( &newX509Action
);
521 newMenu
.addAction( &newOpenPGPAction
);
523 newTB
->setMenu( &newMenu
);
529 DirectoryServicesWidget::DirectoryServicesWidget( QWidget
* p
, Qt::WindowFlags f
)
530 : QWidget( p
, f
), d( new Private( this ) )
536 DirectoryServicesWidget::~DirectoryServicesWidget() {
540 void DirectoryServicesWidget::setAllowedSchemes( Schemes schemes
) {
541 d
->delegate
.setAllowedSchemes( schemes
);
542 d
->showHideColumns();
545 DirectoryServicesWidget::Schemes
DirectoryServicesWidget::allowedSchemes() const {
546 return d
->delegate
.allowedSchemes();
549 void DirectoryServicesWidget::setAllowedProtocols( Protocols protocols
) {
550 if ( d
->protocols
== protocols
)
552 d
->protocols
= protocols
;
553 d
->showHideColumns();
554 d
->enableDisableActions();
557 DirectoryServicesWidget::Protocols
DirectoryServicesWidget::allowedProtocols() const {
561 void DirectoryServicesWidget::setReadOnlyProtocols( Protocols protocols
) {
562 if ( d
->readOnlyProtocols
== protocols
)
564 d
->readOnlyProtocols
= protocols
;
565 d
->model
.setOpenPGPReadOnly( protocols
& OpenPGPProtocol
);
566 d
->model
.setX509ReadOnly( protocols
& X509Protocol
);
567 d
->enableDisableActions();
570 DirectoryServicesWidget::Protocols
DirectoryServicesWidget::readOnlyProtocols() const {
571 return d
->readOnlyProtocols
;
574 void DirectoryServicesWidget::addOpenPGPServices( const KUrl::List
& urls
) {
575 Q_FOREACH( const KUrl
& url
, urls
)
576 d
->model
.addOpenPGPService( url
);
579 KUrl::List
DirectoryServicesWidget::openPGPServices() const {
581 for ( unsigned int i
= 0, end
= d
->model
.numServices() ; i
!= end
; ++i
)
582 if ( d
->model
.isOpenPGPService( i
) )
583 result
.push_back( d
->model
.service( i
) );
587 void DirectoryServicesWidget::addX509Services( const KUrl::List
& urls
) {
588 Q_FOREACH( const KUrl
& url
, urls
)
589 d
->model
.addX509Service( url
);
592 KUrl::List
DirectoryServicesWidget::x509Services() const {
594 for ( unsigned int i
= 0, end
= d
->model
.numServices() ; i
!= end
; ++i
)
595 if ( d
->model
.isX509Service( i
) )
596 result
.push_back( d
->model
.service( i
) );
600 void DirectoryServicesWidget::clear() {
601 if ( !d
->model
.numServices() )
607 void DirectoryServicesWidget::Private::showHideColumns() {
608 QHeaderView
* const hv
= ui
.treeView
->header();
610 // don't show 'scheme' column when only accepting X509Protocol (###?)
611 hv
->setSectionHidden( Model::Scheme
, protocols
== X509Protocol
);
612 // hide the protocol selection columns for if only one protocol is allowed anyway:
613 hv
->setSectionHidden( Model::X509
, protocols
!= AllProtocols
);
614 hv
->setSectionHidden( Model::OpenPGP
, protocols
!= AllProtocols
);
621 QVariant
Model::headerData( int section
, Qt::Orientation orientation
, int role
) const {
622 if ( orientation
== Qt::Horizontal
)
623 if ( role
== Qt::ToolTipRole
)
624 return toolTipForColumn( section
);
625 else if ( role
== Qt::DisplayRole
)
627 case Scheme
: return i18n("Scheme");
628 case Host
: return i18n("Server Name");
629 case Port
: return i18n("Server Port");
630 case BaseDN
: return i18n("Base DN");
631 case UserName
: return i18n("User Name");
632 case Password
: return i18n("Password");
633 case X509
: return i18n("X.509");
634 case OpenPGP
: return i18n("OpenPGP");
635 default: return QVariant();
640 return QAbstractTableModel::headerData( section
, orientation
, role
);
643 QVariant
Model::data( const QModelIndex
& index
, int role
) const {
644 const unsigned int row
= index
.row();
645 if ( index
.isValid() && row
< m_items
.size() )
647 case Qt::ToolTipRole
: {
648 const QString tt
= toolTipForColumn( index
.column() );
649 if ( !isReadOnlyRow( index
.row() ) )
653 ? i18n("(read-only)")
654 : i18nc("amended tooltip; %1: original tooltip",
655 "%1 (read-only)", tt
);
657 case Qt::DisplayRole
:
659 switch ( index
.column() ) {
661 return display_scheme( m_items
[row
].url
);
663 return display_host( m_items
[row
].url
);
665 return display_port( m_items
[row
].url
);
667 if ( isLdapRow( row
) )
668 return KUrl::fromPercentEncoding( m_items
[row
].url
.query().mid( 1 ).toLatin1() ); // decode query and skip leading '?'
672 return m_items
[row
].url
.user();
674 return m_items
[row
].url
.pass();
680 case Qt::CheckStateRole
:
681 switch ( index
.column() ) {
683 return m_items
[row
].x509
&& isLdapRow( row
) ? Qt::Checked
: Qt::Unchecked
;
685 return m_items
[row
].pgp
? Qt::Checked
: Qt::Unchecked
;
693 bool Model::isLdapRow( unsigned int row
) const {
694 if ( row
>= m_items
.size() )
696 return is_ldap_scheme( m_items
[row
].url
);
699 Qt::ItemFlags
Model::flags( const QModelIndex
& index
) const {
700 const unsigned int row
= index
.row();
701 Qt::ItemFlags flags
= QAbstractTableModel::flags( index
);
702 if ( isReadOnlyRow( row
) )
703 flags
&= ~Qt::ItemIsSelectable
;
704 if ( index
.isValid() && row
< m_items
.size() )
705 switch ( index
.column() ) {
707 switch ( m_schemes
) {
709 if ( !isReadOnlyRow( row
) )
710 return flags
| Qt::ItemIsEditable
;
712 case DirectoryServicesWidget::HKP
:
713 case DirectoryServicesWidget::HTTP
:
714 case DirectoryServicesWidget::FTP
:
715 case DirectoryServicesWidget::LDAP
:
716 // only one scheme allowed -> no editing possible
717 return flags
& ~(Qt::ItemIsEditable
|Qt::ItemIsEnabled
) ;
721 if ( isReadOnlyRow( row
) )
722 return flags
& ~(Qt::ItemIsEnabled
|Qt::ItemIsEnabled
) ;
724 return flags
| Qt::ItemIsEditable
;
726 if ( isLdapRow( row
) && !isReadOnlyRow( row
) )
727 return flags
| Qt::ItemIsEditable
;
729 return flags
& ~(Qt::ItemIsEditable
|Qt::ItemIsEnabled
) ;
732 if ( isReadOnlyRow( row
) )
733 return flags
& ~(Qt::ItemIsEditable
|Qt::ItemIsEnabled
) ;
735 return flags
| Qt::ItemIsEditable
;
737 if ( !isLdapRow( row
) )
738 return flags
& ~(Qt::ItemIsUserCheckable
|Qt::ItemIsEnabled
) ;
741 if ( isReadOnlyRow( row
) )
742 return flags
& ~(Qt::ItemIsUserCheckable
|Qt::ItemIsEnabled
) ;
744 return flags
| Qt::ItemIsUserCheckable
;
749 bool Model::setData( const QModelIndex
& idx
, const QVariant
& value
, int role
) {
750 const unsigned int row
= idx
.row();
751 if ( !idx
.isValid() || row
>= m_items
.size() )
753 if ( isReadOnlyRow( row
) )
755 if ( !doSetData( row
, idx
.column(), value
, role
) )
757 emit
dataChanged( idx
, idx
);
761 bool Model::doSetData( unsigned int row
, unsigned int column
, const QVariant
& value
, int role
) {
762 if ( role
== Qt::EditRole
)
765 if ( is_default_port( m_items
[row
].url
) ) {
766 // drag the port along with scheme changes
767 m_items
[row
].url
.setPort( -1 );
768 const QModelIndex changed
= index( row
, Port
);
769 emit
dataChanged( changed
, changed
);
771 m_items
[row
].url
.setProtocol( value
.toString() );
774 if ( display_host( m_items
[row
].url
) != m_items
[row
].url
.host() ) {
775 m_items
[row
].url
.setProtocol( display_scheme( m_items
[row
].url
) );
776 m_items
[row
].url
.setPath( "/" );
778 m_items
[row
].url
.setHost( value
.toString() );
781 if ( value
.toUInt() == default_port( display_scheme( m_items
[row
].url
) ) )
782 m_items
[row
].url
.setPort( -1 );
784 m_items
[row
].url
.setPort( value
.toUInt() );
787 if ( value
.toString().isEmpty() ) {
788 m_items
[row
].url
.setPath( QString() );
789 m_items
[row
].url
.setQuery( QString() );
791 m_items
[row
].url
.setPath( "/" ); // workaround KUrl parsing bug
792 m_items
[row
].url
.setQuery( value
.toString() );
796 m_items
[row
].url
.setUser( value
.toString() );
799 m_items
[row
].url
.setPass( value
.toString() );
802 if ( role
== Qt::CheckStateRole
)
805 m_items
[row
].x509
= value
.toInt() == Qt::Checked
;
809 const bool on
= value
.toInt() == Qt::Checked
;
811 setExclusivePgpFlag( row
);
813 m_items
[row
].pgp
= false;
820 void Model::setExclusivePgpFlag( unsigned int row
) {
821 if ( row
>= m_items
.size() || m_items
[row
].pgp
)
823 m_items
[row
].pgp
= true; // dataChanged() for this one is supposed to be emitted by the caller
824 for ( unsigned int i
= 0, end
= m_items
.size() ; i
< end
; ++i
)
826 if ( m_items
[i
].pgp
) {
827 m_items
[i
].pgp
= false;
828 const QModelIndex changed
= index( i
, OpenPGP
);
829 emit
dataChanged( changed
, changed
);
835 QString
Model::toolTipForColumn( int column
) {
837 case Scheme
: return i18n("Select the access protocol (scheme) that the "
838 "directory service is available through.");
839 case Host
: return i18n("Enter the name or IP address of the server "
840 "hosting the directory service.");
841 case Port
: return i18n("<b>(Optional, the default is fine in most cases)</b> "
842 "Pick the port number the directory service is "
844 case BaseDN
: return i18n("<b>(Only for LDAP)</b> "
845 "Enter the base DN for this LDAP server to "
846 "limit searches to only that subtree of the directory.");
847 case UserName
: return i18n("<b>(Optional)</b> "
848 "Enter your user name here, if needed.");
849 case Password
: return i18n("<b>(Optional, not recommended)</b> "
850 "Enter your password here, if needed. "
851 "Note that the password will be saved in the clear "
852 "in a config file in your home directory.");
853 case X509
: return i18n("Check this column if this directory service is "
854 "providing S/MIME (X.509) certificates.");
855 case OpenPGP
: return i18n("Check this column if this directory service is "
856 "providing OpenPGP certificates.");
862 #include "directoryserviceswidget.moc"
863 #include "moc_directoryserviceswidget.cpp"