mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 10:52:52 +00:00
865 lines
32 KiB
C++
865 lines
32 KiB
C++
/*
|
||
directoryserviceswidget.cpp
|
||
|
||
This file is part of Kleopatra, the KDE keymanager
|
||
Copyright (c) 2001,2002,2004 Klar<61>vdalens Datakonsult AB
|
||
|
||
Kleopatra is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2 of the License, or
|
||
(at your option) any later version.
|
||
|
||
Kleopatra is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
In addition, as a special exception, the copyright holders give
|
||
permission to link the code of this program with any edition of
|
||
the Qt library by Trolltech AS, Norway (or with modified versions
|
||
of Qt that use the same license as Qt), and distribute linked
|
||
combinations including the two. You must obey the GNU General
|
||
Public License in all respects for all of the code used other than
|
||
Qt. If you modify this file, you may extend this exception to
|
||
your version of the file, but you are not obligated to do so. If
|
||
you do not wish to do so, delete this exception statement from
|
||
your version.
|
||
*/
|
||
|
||
#include "directoryserviceswidget.h"
|
||
|
||
#include "ui_directoryserviceswidget.h"
|
||
|
||
#include <KIcon>
|
||
#include <KDebug>
|
||
#include <KLocale>
|
||
|
||
#include <QItemDelegate>
|
||
#include <QAbstractTableModel>
|
||
#include <QSpinBox>
|
||
#include <QComboBox>
|
||
#include <QHeaderView>
|
||
#include <QMenu>
|
||
#include <QAction>
|
||
|
||
#include <boost/bind.hpp>
|
||
|
||
#include <vector>
|
||
|
||
#include <climits>
|
||
#include <cassert>
|
||
#include <algorithm>
|
||
#include <functional>
|
||
|
||
using namespace Kleo;
|
||
using namespace boost;
|
||
|
||
namespace {
|
||
|
||
static KUrl defaultX509Service() {
|
||
KUrl url;
|
||
url.setScheme( QLatin1String("ldap") );
|
||
url.setHost( i18nc("default server name, keep it a valid domain name, ie. no spaces", "server") );
|
||
return url;
|
||
}
|
||
static KUrl defaultOpenPGPService() {
|
||
KUrl url;
|
||
url.setScheme( QLatin1String("hkp") );
|
||
url.setHost( QLatin1String("keys.gnupg.net") );
|
||
return url;
|
||
}
|
||
|
||
static bool is_ldap_scheme( const KUrl & url ) {
|
||
const QString scheme = url.protocol();
|
||
return QString::compare( scheme, QLatin1String( "ldap" ), Qt::CaseInsensitive ) == 0
|
||
|| QString::compare( scheme, QLatin1String( "ldaps" ), Qt::CaseInsensitive ) == 0;
|
||
}
|
||
|
||
static const struct {
|
||
const char label[6];
|
||
unsigned short port;
|
||
DirectoryServicesWidget::Scheme base;
|
||
} protocols[] = {
|
||
{ I18N_NOOP("hkp"), 11371, DirectoryServicesWidget::HKP },
|
||
{ I18N_NOOP("http"), 80, DirectoryServicesWidget::HTTP },
|
||
{ I18N_NOOP("https"), 443, DirectoryServicesWidget::HTTP },
|
||
{ I18N_NOOP("ftp"), 21, DirectoryServicesWidget::FTP },
|
||
{ I18N_NOOP("ftps"), 990, DirectoryServicesWidget::FTP },
|
||
{ I18N_NOOP("ldap"), 389, DirectoryServicesWidget::LDAP },
|
||
{ I18N_NOOP("ldaps"), 636, DirectoryServicesWidget::LDAP },
|
||
};
|
||
static const unsigned int numProtocols = sizeof protocols / sizeof *protocols;
|
||
|
||
static unsigned short default_port( const QString & scheme ) {
|
||
for ( unsigned int i = 0 ; i < numProtocols ; ++i )
|
||
if ( QString::compare( scheme, QLatin1String( protocols[i].label ), Qt::CaseInsensitive ) == 0 )
|
||
return protocols[i].port;
|
||
return 0;
|
||
}
|
||
|
||
static QString display_scheme( const KUrl & url ) {
|
||
if ( url.scheme().isEmpty() )
|
||
return QLatin1String( "hkp" );
|
||
else
|
||
return url.scheme();
|
||
}
|
||
|
||
static QString display_host( const KUrl & url ) {
|
||
// work around "subkeys.pgp.net" being interpreted as a path, not host
|
||
if ( url.host().isEmpty() )
|
||
return url.path();
|
||
else
|
||
return url.host();
|
||
}
|
||
|
||
static unsigned short display_port( const KUrl & url ) {
|
||
if ( url.port() > 0 )
|
||
return url.port();
|
||
else
|
||
return default_port( display_scheme( url ) );
|
||
}
|
||
|
||
static bool is_default_port( const KUrl & url ) {
|
||
return display_port( url ) == default_port( display_scheme( url ) ) ;
|
||
}
|
||
|
||
static QRect calculate_geometry( const QRect & cell, const QSize & sizeHint ) {
|
||
const int height = qMax( cell.height(), sizeHint.height() );
|
||
return QRect( cell.left(), cell.top() - ( height - cell.height() ) / 2,
|
||
cell.width(), height );
|
||
}
|
||
|
||
struct KUrl_compare : std::binary_function<KUrl,KUrl,bool> {
|
||
bool operator()( const KUrl & lhs, const KUrl & rhs ) const {
|
||
return QString::compare( display_scheme( lhs ), display_scheme( rhs ), Qt::CaseInsensitive ) == 0
|
||
&& QString::compare( display_host( lhs ), display_host( rhs ), Qt::CaseInsensitive ) == 0
|
||
&& lhs.port() == rhs.port()
|
||
&& lhs.user() == rhs.user()
|
||
// ... ignore password...
|
||
&& ( !is_ldap_scheme( lhs )
|
||
|| KUrl::fromPercentEncoding( lhs.query().mid( 1 ).toLatin1() )
|
||
== KUrl::fromPercentEncoding( rhs.query().mid( 1 ).toLatin1() ) ) ;
|
||
}
|
||
};
|
||
|
||
class Model : public QAbstractTableModel {
|
||
Q_OBJECT
|
||
public:
|
||
explicit Model( QObject * parent=0 )
|
||
: QAbstractTableModel( parent ),
|
||
m_items(),
|
||
m_openPGPReadOnly( false ),
|
||
m_x509ReadOnly( false ),
|
||
m_schemes( DirectoryServicesWidget::AllSchemes )
|
||
{
|
||
|
||
}
|
||
|
||
void setOpenPGPReadOnly( bool ro ) {
|
||
if ( ro == m_openPGPReadOnly )
|
||
return;
|
||
m_openPGPReadOnly = ro;
|
||
for ( unsigned int row = 0, end = rowCount() ; row != end ; ++row )
|
||
if ( isOpenPGPService( row ) )
|
||
emit dataChanged( index( row, 0 ), index( row, NumColumns ) );
|
||
}
|
||
|
||
void setX509ReadOnly( bool ro ) {
|
||
if ( ro == m_x509ReadOnly )
|
||
return;
|
||
m_x509ReadOnly = ro;
|
||
for ( unsigned int row = 0, end = rowCount() ; row != end ; ++row )
|
||
if ( isX509Service( row ) )
|
||
emit dataChanged( index( row, 0 ), index( row, NumColumns ) );
|
||
}
|
||
|
||
QModelIndex addOpenPGPService( const KUrl & url, bool force=false ) {
|
||
return addService( url, false, true, force );
|
||
}
|
||
QModelIndex addX509Service( const KUrl & url, bool force=false ) {
|
||
return addService( url, true, false, force );
|
||
}
|
||
QModelIndex addService( const KUrl & url, bool x509, bool pgp, bool force ) {
|
||
const std::vector<Item>::iterator it = force ? m_items.end() : findExistingUrl( url ) ;
|
||
unsigned int row;
|
||
if ( it != m_items.end() ) {
|
||
// existing item:
|
||
it->x509 |= x509;
|
||
it->pgp |= pgp;
|
||
row = it - m_items.begin() ;
|
||
emit dataChanged( index( row, std::min( X509, OpenPGP ) ), index( row, std::max( X509, OpenPGP ) ) );
|
||
} else {
|
||
// append new item
|
||
const Item item = { url, x509, pgp };
|
||
row = m_items.size();
|
||
beginInsertRows( QModelIndex(), row, row );
|
||
m_items.push_back( item );
|
||
endInsertRows();
|
||
}
|
||
return index( row, firstEditableColumn( row ) );
|
||
}
|
||
|
||
unsigned int numServices() const { return m_items.size(); }
|
||
bool isOpenPGPService( unsigned int row ) const { return row < m_items.size() && m_items[row].pgp; }
|
||
bool isX509Service( unsigned int row ) const { return row < m_items.size() && m_items[row].x509 && isLdapRow( row ) ; }
|
||
KUrl service( unsigned int row ) const { return row < m_items.size() ? m_items[row].url : KUrl() ; }
|
||
|
||
bool isReadOnlyRow( unsigned int row ) const {
|
||
return ( isX509Service( row ) && m_x509ReadOnly )
|
||
|| ( isOpenPGPService( row ) && m_openPGPReadOnly );
|
||
}
|
||
|
||
enum Columns {
|
||
Scheme,
|
||
Host,
|
||
Port,
|
||
BaseDN,
|
||
UserName,
|
||
Password,
|
||
X509,
|
||
OpenPGP,
|
||
|
||
NumColumns
|
||
};
|
||
|
||
QModelIndex duplicateRow( unsigned int row ) {
|
||
if ( row >= m_items.size() )
|
||
return QModelIndex();
|
||
|
||
beginInsertRows( QModelIndex(), row+1, row+1 );
|
||
m_items.insert( m_items.begin() + row + 1, m_items[row] );
|
||
if ( m_items[row].pgp )
|
||
m_items[row+1].pgp = false; // enforce pgp exclusivitiy
|
||
endInsertRows();
|
||
return index( row+1, 0 );
|
||
}
|
||
|
||
void deleteRow( unsigned int row ) {
|
||
if ( row >= m_items.size() )
|
||
return;
|
||
|
||
beginRemoveRows( QModelIndex(), row, row );
|
||
m_items.erase( m_items.begin() + row );
|
||
endInsertRows();
|
||
}
|
||
|
||
void clear() {
|
||
if ( m_items.empty() )
|
||
return;
|
||
beginRemoveRows( QModelIndex(), 0, m_items.size()-1 );
|
||
m_items.clear();
|
||
endRemoveRows();
|
||
}
|
||
|
||
/* reimp */ int columnCount( const QModelIndex & =QModelIndex() ) const { return NumColumns; }
|
||
/* reimp */ int rowCount( const QModelIndex & =QModelIndex() ) const { return m_items.size(); }
|
||
|
||
/* reimp */ QVariant data( const QModelIndex & idx, int role ) const;
|
||
/* reimp */ QVariant headerData( int section, Qt::Orientation o, int role ) const;
|
||
|
||
/* reimp */ Qt::ItemFlags flags( const QModelIndex & idx ) const;
|
||
/* reimp */ bool setData( const QModelIndex & idx, const QVariant & value, int role );
|
||
|
||
private:
|
||
bool doSetData( unsigned int row, unsigned int column, const QVariant & value, int role );
|
||
void setExclusivePgpFlag( unsigned int row );
|
||
|
||
static QString toolTipForColumn( int column );
|
||
bool isLdapRow( unsigned int row ) const;
|
||
int firstEditableColumn( unsigned int ) const {
|
||
return Host;
|
||
}
|
||
|
||
private:
|
||
struct Item {
|
||
KUrl url;
|
||
bool x509 : 1;
|
||
bool pgp : 1;
|
||
};
|
||
std::vector<Item> m_items;
|
||
bool m_openPGPReadOnly : 1;
|
||
bool m_x509ReadOnly : 1;
|
||
DirectoryServicesWidget::Schemes m_schemes;
|
||
|
||
private:
|
||
std::vector<Item>::iterator findExistingUrl( const KUrl & url ) {
|
||
return std::find_if( m_items.begin(), m_items.end(),
|
||
boost::bind( KUrl_compare(), url, boost::bind( &Item::url, _1 ) ) );
|
||
}
|
||
};
|
||
|
||
class Delegate : public QItemDelegate {
|
||
Q_OBJECT
|
||
public:
|
||
explicit Delegate( QObject * parent=0 )
|
||
: QItemDelegate( parent ),
|
||
m_schemes( DirectoryServicesWidget::AllSchemes )
|
||
{
|
||
|
||
}
|
||
|
||
void setAllowedSchemes( const DirectoryServicesWidget::Schemes schemes ) {
|
||
m_schemes = schemes;
|
||
}
|
||
DirectoryServicesWidget::Schemes allowedSchemes() const { return m_schemes; }
|
||
|
||
/* reimp */
|
||
QWidget * createEditor( QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & idx ) const {
|
||
switch ( idx.column() ) {
|
||
case Model::Scheme:
|
||
return createSchemeWidget( parent );
|
||
case Model::Port:
|
||
return createPortWidget( parent );
|
||
}
|
||
return QItemDelegate::createEditor( parent, option, idx );
|
||
}
|
||
|
||
/* reimp */
|
||
void setEditorData( QWidget * editor, const QModelIndex & idx ) const {
|
||
switch ( idx.column() ) {
|
||
case Model::Scheme:
|
||
setSchemeEditorData( qobject_cast<QComboBox*>( editor ), idx.data( Qt::EditRole ).toString() );
|
||
break;
|
||
case Model::Port:
|
||
setPortEditorData( qobject_cast<QSpinBox*>( editor ), idx.data( Qt::EditRole ).toInt() );
|
||
break;
|
||
default:
|
||
QItemDelegate::setEditorData( editor, idx );
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* reimp */
|
||
void setModelData( QWidget * editor, QAbstractItemModel * model, const QModelIndex & idx ) const {
|
||
switch ( idx.column() ) {
|
||
case Model::Scheme:
|
||
setSchemeModelData( qobject_cast<QComboBox*>( editor ), model, idx );
|
||
break;
|
||
case Model::Port:
|
||
setPortModelData( qobject_cast<QSpinBox*>( editor ), model, idx );
|
||
break;
|
||
default:
|
||
QItemDelegate::setModelData( editor, model, idx );
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* reimp */
|
||
void updateEditorGeometry( QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
|
||
if ( index.column() == Model::Scheme || index.column() == Model::Port )
|
||
editor->setGeometry( calculate_geometry( option.rect, editor->sizeHint() ) );
|
||
else
|
||
QItemDelegate::updateEditorGeometry( editor, option, index );
|
||
}
|
||
|
||
private:
|
||
QWidget * createSchemeWidget( QWidget * parent ) const {
|
||
if ( !m_schemes )
|
||
return 0;
|
||
QComboBox * cb = new QComboBox( parent );
|
||
for ( unsigned int i = 0 ; i < numProtocols ; ++i )
|
||
if ( m_schemes & protocols[i].base )
|
||
cb->addItem( i18n( protocols[i].label ), QLatin1String(protocols[i].label) );
|
||
assert( cb->count() > 0 );
|
||
return cb;
|
||
}
|
||
void setSchemeEditorData( QComboBox * cb, const QString & scheme ) const {
|
||
assert( cb );
|
||
cb->setCurrentIndex( cb->findData( scheme, Qt::UserRole, Qt::MatchFixedString ) );
|
||
}
|
||
void setSchemeModelData( const QComboBox * cb, QAbstractItemModel * model, const QModelIndex & idx ) const {
|
||
assert( cb );
|
||
assert( model );
|
||
model->setData( idx, cb->itemData( cb->currentIndex() ) );
|
||
}
|
||
|
||
QWidget * createPortWidget( QWidget * parent ) const {
|
||
QSpinBox * sb = new QSpinBox( parent );
|
||
sb->setRange( 1, USHRT_MAX ); // valid port numbers
|
||
return sb;
|
||
}
|
||
void setPortEditorData( QSpinBox * sb, unsigned short port ) const {
|
||
assert( sb );
|
||
sb->setValue( port );
|
||
}
|
||
void setPortModelData( const QSpinBox * sb, QAbstractItemModel * model, const QModelIndex & idx ) const {
|
||
assert( sb );
|
||
assert( model );
|
||
model->setData( idx, sb->value() );
|
||
}
|
||
|
||
private:
|
||
DirectoryServicesWidget::Schemes m_schemes;
|
||
};
|
||
|
||
}
|
||
|
||
class DirectoryServicesWidget::Private {
|
||
friend class ::Kleo::DirectoryServicesWidget;
|
||
DirectoryServicesWidget * const q;
|
||
public:
|
||
explicit Private( DirectoryServicesWidget * qq )
|
||
: q( qq ),
|
||
protocols( AllProtocols ),
|
||
readOnlyProtocols( NoProtocol ),
|
||
model(),
|
||
delegate(),
|
||
ui( q )
|
||
{
|
||
ui.treeView->setModel( &model );
|
||
ui.treeView->setItemDelegate( &delegate );
|
||
|
||
connect( &model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
|
||
q, SIGNAL(changed()) );
|
||
connect( &model, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||
q, SIGNAL(changed()) );
|
||
connect( &model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||
q, SIGNAL(changed()) );
|
||
connect( ui.treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||
q, SLOT(slotSelectionChanged()) );
|
||
|
||
slotShowUserAndPasswordToggled( false );
|
||
}
|
||
|
||
private:
|
||
void slotNewClicked() {
|
||
int row = selectedRow();
|
||
if ( row < 0 )
|
||
row = currentRow();
|
||
if ( row < 0 || model.isReadOnlyRow( row ) )
|
||
if ( protocols & OpenPGPProtocol )
|
||
slotNewOpenPGPClicked();
|
||
else if ( protocols & X509Protocol )
|
||
slotNewX509Clicked();
|
||
else
|
||
assert( !"This should not happen.");
|
||
else
|
||
edit( model.duplicateRow( row ) );
|
||
}
|
||
void edit( const QModelIndex & index ) {
|
||
if ( index.isValid() ) {
|
||
ui.treeView->clearSelection();
|
||
ui.treeView->selectionModel()->setCurrentIndex( index, QItemSelectionModel::Select|QItemSelectionModel::Rows );
|
||
ui.treeView->edit( index );
|
||
}
|
||
}
|
||
void slotNewX509Clicked() {
|
||
edit( model.addX509Service( defaultX509Service(), true ) );
|
||
}
|
||
void slotNewOpenPGPClicked() {
|
||
edit( model.addOpenPGPService( defaultOpenPGPService(), true ) );
|
||
}
|
||
void slotDeleteClicked() {
|
||
model.deleteRow( selectedRow() );
|
||
}
|
||
void slotSelectionChanged() {
|
||
enableDisableActions();
|
||
}
|
||
void slotShowUserAndPasswordToggled( bool on ) {
|
||
QHeaderView * const hv = ui.treeView->header();
|
||
assert( hv );
|
||
hv->setSectionHidden( Model::UserName, !on );
|
||
hv->setSectionHidden( Model::Password, !on );
|
||
}
|
||
|
||
int selectedRow() const {
|
||
const QModelIndexList mil = ui.treeView->selectionModel()->selectedRows();
|
||
return mil.empty() ? -1 : mil.front().row();
|
||
}
|
||
int currentRow() const {
|
||
const QModelIndex idx = ui.treeView->selectionModel()->currentIndex();
|
||
return idx.isValid() ? idx.row() : -1 ;
|
||
}
|
||
|
||
void showHideColumns();
|
||
|
||
void enableDisableActions() {
|
||
const bool x509 = ( protocols & X509Protocol ) && !( readOnlyProtocols & X509Protocol ) ;
|
||
const bool pgp = ( protocols & OpenPGPProtocol ) && !( readOnlyProtocols & OpenPGPProtocol ) ;
|
||
ui.newX509Action.setEnabled( x509 );
|
||
ui.newOpenPGPAction.setEnabled( pgp );
|
||
if ( x509 && pgp ) {
|
||
ui.newTB->setMenu( &ui.newMenu );
|
||
ui.newTB->setPopupMode( QToolButton::MenuButtonPopup );
|
||
} else {
|
||
ui.newTB->setMenu( 0 );
|
||
ui.newTB->setPopupMode( QToolButton::DelayedPopup );
|
||
ui.newTB->setEnabled( x509 || pgp );
|
||
}
|
||
const int row = selectedRow();
|
||
ui.deleteTB->setEnabled( row >= 0 && !model.isReadOnlyRow( row ) );
|
||
}
|
||
|
||
private:
|
||
Protocols protocols;
|
||
Protocols readOnlyProtocols;
|
||
Model model;
|
||
Delegate delegate;
|
||
struct UI : Ui_DirectoryServicesWidget {
|
||
QAction newX509Action;
|
||
QAction newOpenPGPAction;
|
||
QMenu newMenu;
|
||
|
||
explicit UI( DirectoryServicesWidget * q )
|
||
: Ui_DirectoryServicesWidget(),
|
||
newX509Action( i18nc("New X.509 Directory Server", "X.509"), q ),
|
||
newOpenPGPAction( i18nc("New OpenPGP Directory Server", "OpenPGP"), q ),
|
||
newMenu( q )
|
||
{
|
||
newX509Action.setObjectName( QLatin1String("newX509Action") );
|
||
newOpenPGPAction.setObjectName( QLatin1String("newOpenPGPAction") );
|
||
newMenu.setObjectName( QLatin1String("newMenu") );
|
||
|
||
setupUi( q );
|
||
|
||
connect( &newX509Action, SIGNAL(triggered()), q, SLOT(slotNewX509Clicked()) );
|
||
connect( &newOpenPGPAction, SIGNAL(triggered()), q, SLOT(slotNewOpenPGPClicked()) );
|
||
|
||
newMenu.addAction( &newX509Action );
|
||
newMenu.addAction( &newOpenPGPAction );
|
||
|
||
newTB->setMenu( &newMenu );
|
||
}
|
||
|
||
} ui;
|
||
};
|
||
|
||
DirectoryServicesWidget::DirectoryServicesWidget( QWidget * p, Qt::WindowFlags f )
|
||
: QWidget( p, f ), d( new Private( this ) )
|
||
{
|
||
|
||
}
|
||
|
||
|
||
DirectoryServicesWidget::~DirectoryServicesWidget() {
|
||
delete d;
|
||
}
|
||
|
||
void DirectoryServicesWidget::setAllowedSchemes( Schemes schemes ) {
|
||
d->delegate.setAllowedSchemes( schemes );
|
||
d->showHideColumns();
|
||
}
|
||
|
||
DirectoryServicesWidget::Schemes DirectoryServicesWidget::allowedSchemes() const {
|
||
return d->delegate.allowedSchemes();
|
||
}
|
||
|
||
void DirectoryServicesWidget::setAllowedProtocols( Protocols protocols ) {
|
||
if ( d->protocols == protocols )
|
||
return;
|
||
d->protocols = protocols;
|
||
d->showHideColumns();
|
||
d->enableDisableActions();
|
||
}
|
||
|
||
DirectoryServicesWidget::Protocols DirectoryServicesWidget::allowedProtocols() const {
|
||
return d->protocols;
|
||
}
|
||
|
||
void DirectoryServicesWidget::setReadOnlyProtocols( Protocols protocols ) {
|
||
if ( d->readOnlyProtocols == protocols )
|
||
return;
|
||
d->readOnlyProtocols = protocols;
|
||
d->model.setOpenPGPReadOnly( protocols & OpenPGPProtocol );
|
||
d->model.setX509ReadOnly( protocols & X509Protocol );
|
||
d->enableDisableActions();
|
||
}
|
||
|
||
DirectoryServicesWidget::Protocols DirectoryServicesWidget::readOnlyProtocols() const {
|
||
return d->readOnlyProtocols;
|
||
}
|
||
|
||
void DirectoryServicesWidget::addOpenPGPServices( const KUrl::List & urls ) {
|
||
Q_FOREACH( const KUrl & url, urls )
|
||
d->model.addOpenPGPService( url );
|
||
}
|
||
|
||
KUrl::List DirectoryServicesWidget::openPGPServices() const {
|
||
KUrl::List result;
|
||
for ( unsigned int i = 0, end = d->model.numServices() ; i != end ; ++i )
|
||
if ( d->model.isOpenPGPService( i ) )
|
||
result.push_back( d->model.service( i ) );
|
||
return result;
|
||
}
|
||
|
||
void DirectoryServicesWidget::addX509Services( const KUrl::List & urls ) {
|
||
Q_FOREACH( const KUrl & url, urls )
|
||
d->model.addX509Service( url );
|
||
}
|
||
|
||
KUrl::List DirectoryServicesWidget::x509Services() const {
|
||
KUrl::List result;
|
||
for ( unsigned int i = 0, end = d->model.numServices() ; i != end ; ++i )
|
||
if ( d->model.isX509Service( i ) )
|
||
result.push_back( d->model.service( i ) );
|
||
return result;
|
||
}
|
||
|
||
void DirectoryServicesWidget::clear() {
|
||
if ( !d->model.numServices() )
|
||
return;
|
||
d->model.clear();
|
||
emit changed();
|
||
}
|
||
|
||
void DirectoryServicesWidget::Private::showHideColumns() {
|
||
QHeaderView * const hv = ui.treeView->header();
|
||
assert( hv );
|
||
// don't show 'scheme' column when only accepting X509Protocol (###?)
|
||
hv->setSectionHidden( Model::Scheme, protocols == X509Protocol );
|
||
// hide the protocol selection columns for if only one protocol is allowed anyway:
|
||
hv->setSectionHidden( Model::X509, protocols != AllProtocols );
|
||
hv->setSectionHidden( Model::OpenPGP, protocols != AllProtocols );
|
||
}
|
||
|
||
//
|
||
// Model
|
||
//
|
||
|
||
QVariant Model::headerData( int section, Qt::Orientation orientation, int role ) const {
|
||
if ( orientation == Qt::Horizontal )
|
||
if ( role == Qt::ToolTipRole )
|
||
return toolTipForColumn( section );
|
||
else if ( role == Qt::DisplayRole )
|
||
switch ( section ) {
|
||
case Scheme: return i18n("Scheme");
|
||
case Host: return i18n("Server Name");
|
||
case Port: return i18n("Server Port");
|
||
case BaseDN: return i18n("Base DN");
|
||
case UserName: return i18n("User Name");
|
||
case Password: return i18n("Password");
|
||
case X509: return i18n("X.509");
|
||
case OpenPGP: return i18n("OpenPGP");
|
||
default: return QVariant();
|
||
}
|
||
else
|
||
return QVariant();
|
||
else
|
||
return QAbstractTableModel::headerData( section, orientation, role );
|
||
}
|
||
|
||
QVariant Model::data( const QModelIndex & index, int role ) const {
|
||
const unsigned int row = index.row();
|
||
if ( index.isValid() && row < m_items.size() )
|
||
switch ( role ) {
|
||
case Qt::ToolTipRole: {
|
||
const QString tt = toolTipForColumn( index.column() );
|
||
if ( !isReadOnlyRow( index.row() ) )
|
||
return tt;
|
||
else
|
||
return tt.isEmpty()
|
||
? i18n("(read-only)")
|
||
: i18nc("amended tooltip; %1: original tooltip",
|
||
"%1 (read-only)", tt );
|
||
}
|
||
case Qt::DisplayRole:
|
||
case Qt::EditRole:
|
||
switch ( index.column() ) {
|
||
case Scheme:
|
||
return display_scheme( m_items[row].url );
|
||
case Host:
|
||
return display_host( m_items[row].url );
|
||
case Port:
|
||
return display_port( m_items[row].url );
|
||
case BaseDN:
|
||
if ( isLdapRow( row ) )
|
||
return KUrl::fromPercentEncoding( m_items[row].url.query().mid( 1 ).toLatin1() ); // decode query and skip leading '?'
|
||
else
|
||
return QVariant();
|
||
case UserName:
|
||
return m_items[row].url.user();
|
||
case Password:
|
||
return m_items[row].url.pass();
|
||
case X509:
|
||
case OpenPGP:
|
||
default:
|
||
return QVariant();
|
||
}
|
||
case Qt::CheckStateRole:
|
||
switch ( index.column() ) {
|
||
case X509:
|
||
return m_items[row].x509 && isLdapRow( row ) ? Qt::Checked : Qt::Unchecked ;
|
||
case OpenPGP:
|
||
return m_items[row].pgp ? Qt::Checked : Qt::Unchecked ;
|
||
default:
|
||
return QVariant();
|
||
}
|
||
}
|
||
return QVariant();
|
||
}
|
||
|
||
bool Model::isLdapRow( unsigned int row ) const {
|
||
if ( row >= m_items.size() )
|
||
return false;
|
||
return is_ldap_scheme( m_items[row].url );
|
||
}
|
||
|
||
Qt::ItemFlags Model::flags( const QModelIndex & index ) const {
|
||
const unsigned int row = index.row();
|
||
Qt::ItemFlags flags = QAbstractTableModel::flags( index );
|
||
if ( isReadOnlyRow( row ) )
|
||
flags &= ~Qt::ItemIsSelectable ;
|
||
if ( index.isValid() && row < m_items.size() )
|
||
switch ( index.column() ) {
|
||
case Scheme:
|
||
switch ( m_schemes ) {
|
||
default:
|
||
if ( !isReadOnlyRow( row ) )
|
||
return flags | Qt::ItemIsEditable ;
|
||
// else fall through
|
||
case DirectoryServicesWidget::HKP:
|
||
case DirectoryServicesWidget::HTTP:
|
||
case DirectoryServicesWidget::FTP:
|
||
case DirectoryServicesWidget::LDAP:
|
||
// only one scheme allowed -> no editing possible
|
||
return flags & ~(Qt::ItemIsEditable|Qt::ItemIsEnabled) ;
|
||
}
|
||
case Host:
|
||
case Port:
|
||
if ( isReadOnlyRow( row ) )
|
||
return flags & ~(Qt::ItemIsEditable|Qt::ItemIsEnabled) ;
|
||
else
|
||
return flags | Qt::ItemIsEditable ;
|
||
case BaseDN:
|
||
if ( isLdapRow( row ) && !isReadOnlyRow( row ) )
|
||
return flags | Qt::ItemIsEditable ;
|
||
else
|
||
return flags & ~(Qt::ItemIsEditable|Qt::ItemIsEnabled) ;
|
||
case UserName:
|
||
case Password:
|
||
if ( isReadOnlyRow( row ) )
|
||
return flags & ~(Qt::ItemIsEditable|Qt::ItemIsEnabled) ;
|
||
else
|
||
return flags | Qt::ItemIsEditable ;
|
||
case X509:
|
||
if ( !isLdapRow( row ) )
|
||
return flags & ~(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled) ;
|
||
// fall through
|
||
case OpenPGP:
|
||
if ( isReadOnlyRow( row ) )
|
||
return flags & ~(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled) ;
|
||
else
|
||
return flags | Qt::ItemIsUserCheckable ;
|
||
}
|
||
return flags;
|
||
}
|
||
|
||
bool Model::setData( const QModelIndex & idx, const QVariant & value, int role ) {
|
||
const unsigned int row = idx.row();
|
||
if ( !idx.isValid() || row >= m_items.size() )
|
||
return false;
|
||
if ( isReadOnlyRow( row ) )
|
||
return false;
|
||
if ( !doSetData( row, idx.column(), value, role ) )
|
||
return false;
|
||
emit dataChanged( idx, idx );
|
||
return true;
|
||
}
|
||
|
||
bool Model::doSetData( unsigned int row, unsigned int column, const QVariant & value, int role ) {
|
||
if ( role == Qt::EditRole )
|
||
switch ( column ) {
|
||
case Scheme:
|
||
if ( is_default_port( m_items[row].url ) ) {
|
||
// drag the port along with scheme changes
|
||
m_items[row].url.setPort( -1 );
|
||
const QModelIndex changed = index( row, Port );
|
||
emit dataChanged( changed, changed );
|
||
}
|
||
m_items[row].url.setProtocol( value.toString() );
|
||
return true;
|
||
case Host:
|
||
if ( display_host( m_items[row].url ) != m_items[row].url.host() ) {
|
||
m_items[row].url.setProtocol( display_scheme( m_items[row].url ) );
|
||
m_items[row].url.setPath( QLatin1String("/") );
|
||
}
|
||
m_items[row].url.setHost( value.toString() );
|
||
return true;
|
||
case Port:
|
||
if ( value.toUInt() == default_port( display_scheme( m_items[row].url ) ) )
|
||
m_items[row].url.setPort( -1 );
|
||
else
|
||
m_items[row].url.setPort( value.toUInt() );
|
||
return true;
|
||
case BaseDN:
|
||
if ( value.toString().isEmpty() ) {
|
||
m_items[row].url.setPath( QString() );
|
||
m_items[row].url.setQuery( QString() );
|
||
} else {
|
||
m_items[row].url.setPath( QLatin1String("/") ); // workaround KUrl parsing bug
|
||
m_items[row].url.setQuery( value.toString() );
|
||
}
|
||
return true;
|
||
case UserName:
|
||
m_items[row].url.setUserName( value.toString() );
|
||
return true;
|
||
case Password:
|
||
m_items[row].url.setPassword( value.toString() );
|
||
return true;
|
||
}
|
||
if ( role == Qt::CheckStateRole )
|
||
switch ( column ) {
|
||
case X509:
|
||
m_items[row].x509 = value.toInt() == Qt::Checked ;
|
||
return true;
|
||
case OpenPGP:
|
||
{
|
||
const bool on = value.toInt() == Qt::Checked ;
|
||
if ( on )
|
||
setExclusivePgpFlag( row );
|
||
else
|
||
m_items[row].pgp = false;
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void Model::setExclusivePgpFlag( unsigned int row ) {
|
||
if ( row >= m_items.size() || m_items[row].pgp )
|
||
return;
|
||
m_items[row].pgp = true; // dataChanged() for this one is supposed to be emitted by the caller
|
||
for ( unsigned int i = 0, end = m_items.size() ; i < end ; ++i )
|
||
if ( i != row )
|
||
if ( m_items[i].pgp ) {
|
||
m_items[i].pgp = false;
|
||
const QModelIndex changed = index( i, OpenPGP );
|
||
emit dataChanged( changed, changed );
|
||
break;
|
||
}
|
||
}
|
||
|
||
// static
|
||
QString Model::toolTipForColumn( int column ) {
|
||
switch ( column ) {
|
||
case Scheme: return i18n("Select the access protocol (scheme) that the "
|
||
"directory service is available through.");
|
||
case Host: return i18n("Enter the name or IP address of the server "
|
||
"hosting the directory service.");
|
||
case Port: return i18n("<b>(Optional, the default is fine in most cases)</b> "
|
||
"Pick the port number the directory service is "
|
||
"listening on.");
|
||
case BaseDN: return i18n("<b>(Only for LDAP)</b> "
|
||
"Enter the base DN for this LDAP server to "
|
||
"limit searches to only that subtree of the directory.");
|
||
case UserName: return i18n("<b>(Optional)</b> "
|
||
"Enter your user name here, if needed.");
|
||
case Password: return i18n("<b>(Optional, not recommended)</b> "
|
||
"Enter your password here, if needed. "
|
||
"Note that the password will be saved in the clear "
|
||
"in a config file in your home directory.");
|
||
case X509: return i18n("Check this column if this directory service is "
|
||
"providing S/MIME (X.509) certificates.");
|
||
case OpenPGP: return i18n("Check this column if this directory service is "
|
||
"providing OpenPGP certificates.");
|
||
default:
|
||
return QString();
|
||
}
|
||
}
|
||
|
||
#include "directoryserviceswidget.moc"
|
||
#include "moc_directoryserviceswidget.cpp"
|