diff options
Diffstat (limited to 'certmanager/lib/ui')
34 files changed, 7394 insertions, 0 deletions
diff --git a/certmanager/lib/ui/Makefile.am b/certmanager/lib/ui/Makefile.am new file mode 100644 index 000000000..f381fb64d --- /dev/null +++ b/certmanager/lib/ui/Makefile.am @@ -0,0 +1,42 @@ + +INCLUDES = -I$(top_srcdir)/libkdenetwork \ + -I$(top_srcdir)/libkpgp \ + -I$(top_srcdir)/certmanager/lib \ + $(GPGME_CFLAGS) $(all_includes) + +noinst_LTLIBRARIES = libkleopatra_ui.la + +libkleopatra_ui_la_SOURCES = \ + kdhorizontalline.cpp \ + messagebox.cpp \ + progressbar.cpp \ + progressdialog.cpp \ + keylistview.cpp \ + keyselectiondialog.cpp \ + keyrequester.cpp \ + passphrasedialog.cpp \ + keyapprovaldialog.cpp \ + backendconfigwidget.cpp \ + dnattributeorderconfigwidget.cpp \ + cryptoconfigmodule.cpp \ + cryptoconfigdialog.cpp \ + directoryserviceswidgetbase.ui \ + directoryserviceswidget.cpp \ + adddirectoryservicedialog.ui \ + adddirectoryservicedialogimpl.cpp + +kleodir = $(includedir)/kleo +kleo_HEADERS = \ + kdhorizontalline.h \ + messagebox.h \ + progressbar.h \ + progressdialog.h \ + keylistview.h \ + keyselectiondialog.h \ + keyrequester.h \ + passphrasedialog.h \ + keyapprovaldialog.h \ + backendconfigwidget.h \ + dnattributeorderconfigwidget.h + +METASOURCES = AUTO diff --git a/certmanager/lib/ui/adddirectoryservicedialog.ui b/certmanager/lib/ui/adddirectoryservicedialog.ui new file mode 100644 index 000000000..98e171887 --- /dev/null +++ b/certmanager/lib/ui/adddirectoryservicedialog.ui @@ -0,0 +1,207 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>AddDirectoryServiceDialog</class> +<widget class="QDialog"> + <property name="name"> + <cstring>AddDirectoryServiceDialog</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>389</width> + <height>257</height> + </rect> + </property> + <property name="caption"> + <string>Add or Change Directory Service</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>serverNameLA</cstring> + </property> + <property name="text"> + <string>&Server name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>serverNameED</cstring> + </property> + </widget> + <widget class="QLineEdit" row="2" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>descriptionED</cstring> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>portED</cstring> + </property> + <property name="text"> + <string>389</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>serverNameED</cstring> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>usernameLA</cstring> + </property> + <property name="text"> + <string>&User name (optional):</string> + </property> + <property name="buddy" stdset="0"> + <cstring>usernameED</cstring> + </property> + </widget> + <spacer row="5" column="3"> + <property name="name"> + <cstring>spacer23</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>60</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>passwordLA</cstring> + </property> + <property name="text"> + <string>Pass&word (optional):</string> + </property> + <property name="buddy" stdset="0"> + <cstring>passwordED</cstring> + </property> + </widget> + <widget class="QPushButton" row="8" column="2"> + <property name="name"> + <cstring>PushButton3</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton" row="8" column="3"> + <property name="name"> + <cstring>PushButton4</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + <widget class="Line" row="6" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <spacer row="7" column="0" rowspan="2" colspan="2"> + <property name="name"> + <cstring>spacer21</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>260</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QLineEdit" row="3" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>usernameED</cstring> + </property> + </widget> + <widget class="QLineEdit" row="4" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>passwordED</cstring> + </property> + <property name="echoMode"> + <enum>Password</enum> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>descriptionLA</cstring> + </property> + <property name="text"> + <string>&Base DN:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>descriptionED</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>portLA</cstring> + </property> + <property name="text"> + <string>&Port:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>portED</cstring> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>PushButton3</sender> + <signal>clicked()</signal> + <receiver>AddDirectoryServiceDialog</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>PushButton4</sender> + <signal>clicked()</signal> + <receiver>AddDirectoryServiceDialog</receiver> + <slot>reject()</slot> + </connection> +</connections> +<tabstops> + <tabstop>serverNameED</tabstop> + <tabstop>portED</tabstop> + <tabstop>descriptionED</tabstop> + <tabstop>usernameED</tabstop> + <tabstop>passwordED</tabstop> + <tabstop>PushButton3</tabstop> + <tabstop>PushButton4</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/certmanager/lib/ui/adddirectoryservicedialogimpl.cpp b/certmanager/lib/ui/adddirectoryservicedialogimpl.cpp new file mode 100644 index 000000000..973266b16 --- /dev/null +++ b/certmanager/lib/ui/adddirectoryservicedialogimpl.cpp @@ -0,0 +1,63 @@ +/* + adddirectoryservicedialogimpl.cpp + + This file is part of Kleopatra, the KDE keymanager + Copyright (c) 2001,2002,2004 Klarälvdalens 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. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "adddirectoryservicedialogimpl.h" + +#include <qvalidator.h> +#include <klineedit.h> + +/* + * Constructs a AddDirectoryServiceDialogImpl which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +AddDirectoryServiceDialogImpl::AddDirectoryServiceDialogImpl( QWidget* parent, const char* name, bool modal, WFlags fl ) + : AddDirectoryServiceDialog( parent, name, modal, fl ) +{ + portED->setValidator( new QIntValidator( 0, 65535, portED ) ); +} + +/* + * Destroys the object and frees any allocated resources + */ +AddDirectoryServiceDialogImpl::~AddDirectoryServiceDialogImpl() +{ + // no need to delete child widgets, Qt does it all for us +} + +#include "adddirectoryservicedialogimpl.moc" diff --git a/certmanager/lib/ui/adddirectoryservicedialogimpl.h b/certmanager/lib/ui/adddirectoryservicedialogimpl.h new file mode 100644 index 000000000..deee06439 --- /dev/null +++ b/certmanager/lib/ui/adddirectoryservicedialogimpl.h @@ -0,0 +1,47 @@ +/* + adddirectoryservicedialogimpl.h + + This file is part of Kleopatra, the KDE keymanager + Copyright (c) 2001,2002,2004 Klarälvdalens 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. +*/ + +#ifndef ADDDIRECTORYSERVICEDIALOGIMPL_H +#define ADDDIRECTORYSERVICEDIALOGIMPL_H +#include "adddirectoryservicedialog.h" + +class AddDirectoryServiceDialogImpl : public AddDirectoryServiceDialog +{ + Q_OBJECT + +public: + AddDirectoryServiceDialogImpl( QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 ); + ~AddDirectoryServiceDialogImpl(); + +}; + +#endif // ADDDIRECTORYSERVICEDIALOGIMPL_H diff --git a/certmanager/lib/ui/backendconfigwidget.cpp b/certmanager/lib/ui/backendconfigwidget.cpp new file mode 100644 index 000000000..c40890a43 --- /dev/null +++ b/certmanager/lib/ui/backendconfigwidget.cpp @@ -0,0 +1,323 @@ +/* -*- c++ -*- + backendconfigwidget.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2002,2004,2005 Klarälvdalens Datakonsult AB + Copyright (c) 2002,2003 Marc Mutz <mutz@kde.org> + + Libkleopatra 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. + + Libkleopatra 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "backendconfigwidget.h" +#include "cryptoconfigdialog.h" + +#include "kleo/cryptobackendfactory.h" +#include "ui/keylistview.h" // for lvi_cast<> + +#include <klistview.h> +#include <kdialog.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <dcopclient.h> + +#include <qpushbutton.h> +#include <qlayout.h> +#include <qheader.h> +#include <qtimer.h> + +#include <assert.h> + +namespace Kleo { + class BackendListView; +} + +class Kleo::BackendConfigWidget::Private { +public: + Kleo::BackendListView * listView; + QPushButton * configureButton; + QPushButton * rescanButton; + Kleo::CryptoBackendFactory * backendFactory; +}; + +namespace Kleo { + class BackendListViewItem; + class ProtocolCheckListItem; +} + +class Kleo::BackendListView : public KListView +{ +public: + BackendListView( BackendConfigWidget* parent, const char* name = 0 ) + : KListView( parent, name ) {} + + /// return backend for currently selected (/current) item. Used by Configure button. + const Kleo::CryptoBackend* currentBackend() const; + + /// return which protocol implementation was chosen (checked) for each type (used when saving) + const Kleo::CryptoBackend* chosenBackend( const char * protocol ); + + /// deselect all except one for a given protocol type (radiobutton-like exclusivity) + void deselectAll( const char * protocol, QCheckListItem* except ); + + void emitChanged() { static_cast<BackendConfigWidget *>( parentWidget() )->emitChanged( true ); } +}; + +// Toplevel listviewitem for a given backend (e.g. "GpgME", "Kgpg/gpg v2") +class Kleo::BackendListViewItem : public QListViewItem +{ +public: + BackendListViewItem( KListView* lv, QListViewItem *prev, const CryptoBackend *cryptoBackend ) + : QListViewItem( lv, prev, cryptoBackend->displayName() ), mCryptoBackend( cryptoBackend ) + {} + + const CryptoBackend *cryptoBackend() const { return mCryptoBackend; } + enum { RTTI = 0x2EAE3BE0, RTTI_MASK = 0xFFFFFFFF }; + int rtti() const { return RTTI; } + +private: + const CryptoBackend *mCryptoBackend; +}; + + +// Checklist item under a BackendListViewItem +// (e.g. "GpgME supports protocol OpenPGP") +class Kleo::ProtocolCheckListItem : public QCheckListItem +{ +public: + ProtocolCheckListItem( BackendListViewItem* blvi, + QListViewItem* prev, const char * protocolName, + const CryptoBackend::Protocol* protocol ) // can be 0 + : QCheckListItem( blvi, prev, itemText( protocolName, protocol ), + QCheckListItem::CheckBox ), + mProtocol( protocol ), mProtocolName( protocolName ) + {} + + enum { RTTI = 0x2EAE3BE1, RTTI_MASK = 0xFFFFFFFF }; + virtual int rtti() const { return RTTI; } + + // can be 0 + const CryptoBackend::Protocol* protocol() const { return mProtocol; } + const char * protocolName() const { return mProtocolName; } + +protected: + virtual void stateChange( bool b ) { + BackendListView* lv = static_cast<BackendListView *>( listView() ); + // "radio-button-like" behavior for the protocol checkboxes + if ( b ) + lv->deselectAll( mProtocolName, this ); + lv->emitChanged(); + QCheckListItem::stateChange( b ); + } + +private: + // Helper for the constructor. + static QString itemText( const char * protocolName, const CryptoBackend::Protocol* protocol ) { + // First one is the generic name (find a nice one for OpenPGP, SMIME) + const QString protoName = qstricmp( protocolName, "openpgp" ) != 0 + ? qstricmp( protocolName, "smime" ) != 0 + ? QString::fromLatin1( protocolName ) + : i18n( "S/MIME" ) + : i18n( "OpenPGP" ); + // second one is implementation name (gpg, gpgsm...) + const QString impName = protocol ? protocol->displayName() : i18n( "failed" ); + return i18n( "Items in Kleo::BackendConfigWidget listview (1: protocol; 2: implementation name)", + "%1 (%2)" ).arg( protoName, impName ); + } + + const CryptoBackend::Protocol* mProtocol; // can be 0 + const char * mProtocolName; +}; + +const Kleo::CryptoBackend* Kleo::BackendListView::currentBackend() const { + const QListViewItem* curItem = currentItem(); + if ( !curItem ) // can't happen + return 0; + if ( lvi_cast<Kleo::ProtocolCheckListItem>( curItem ) ) + curItem = curItem->parent(); + if ( const Kleo::BackendListViewItem * blvi = lvi_cast<Kleo::BackendListViewItem>( curItem ) ) + return blvi->cryptoBackend(); + return 0; +} + +// can't be const method due to QListViewItemIterator (why?) +const Kleo::CryptoBackend* Kleo::BackendListView::chosenBackend( const char * protocolName ) +{ + for ( QListViewItemIterator it( this /*, QListViewItemIterator::Checked doesn't work*/ ) ; + it.current() ; ++it ) + if ( ProtocolCheckListItem * p = lvi_cast<ProtocolCheckListItem>( it.current() ) ) + if ( p->isOn() && qstricmp( p->protocolName(), protocolName ) == 0 ) { + // OK that's the one. Now go up to the parent backend + // (need to do that in the listview since Protocol doesn't know it) + if ( const BackendListViewItem * parItem = lvi_cast<BackendListViewItem>( it.current()->parent() ) ) + return parItem->cryptoBackend(); + } + return 0; +} + +void Kleo::BackendListView::deselectAll( const char * protocolName, QCheckListItem* except ) +{ + for ( QListViewItemIterator it( this /*, QListViewItemIterator::Checked doesn't work*/ ) ; + it.current() ; ++it ) { + if ( it.current() == except ) continue; + if ( ProtocolCheckListItem * p = lvi_cast<ProtocolCheckListItem>( it.current() ) ) + if ( p->isOn() && qstricmp( p->protocolName(), protocolName ) == 0 ) + p->setOn( false ); + } +} + +//// + +Kleo::BackendConfigWidget::BackendConfigWidget( CryptoBackendFactory * factory, QWidget * parent, const char * name, WFlags f ) + : QWidget( parent, name, f ), d( 0 ) +{ + assert( factory ); + d = new Private(); + d->backendFactory = factory; + + QHBoxLayout * hlay = + new QHBoxLayout( this, 0, KDialog::spacingHint() ); + + d->listView = new BackendListView( this, "d->listView" ); + d->listView->addColumn( i18n("Available Backends") ); + d->listView->setAllColumnsShowFocus( true ); + d->listView->setSorting( -1 ); + d->listView->header()->setClickEnabled( false ); + d->listView->setFullWidth( true ); + + hlay->addWidget( d->listView, 1 ); + + connect( d->listView, SIGNAL(selectionChanged(QListViewItem*)), + SLOT(slotSelectionChanged(QListViewItem*)) ); + + QVBoxLayout * vlay = new QVBoxLayout( hlay ); // inherits spacing + + d->configureButton = new QPushButton( i18n("Confi&gure..."), this ); + d->configureButton->setAutoDefault( false ); + vlay->addWidget( d->configureButton ); + + connect( d->configureButton, SIGNAL(clicked()), + SLOT(slotConfigureButtonClicked()) ); + + d->rescanButton = new QPushButton( i18n("Rescan"), this ); + d->rescanButton->setAutoDefault( false ); + vlay->addWidget( d->rescanButton ); + + connect( d->rescanButton, SIGNAL(clicked()), + SLOT(slotRescanButtonClicked()) ); + + vlay->addStretch( 1 ); +} + +Kleo::BackendConfigWidget::~BackendConfigWidget() { + delete d; d = 0; +} + +void Kleo::BackendConfigWidget::load() { + d->listView->clear(); + + unsigned int backendCount = 0; + + // populate the plugin list: + BackendListViewItem * top = 0; + for ( unsigned int i = 0 ; const CryptoBackend * b = d->backendFactory->backend( i ) ; ++i ) { + + top = new Kleo::BackendListViewItem( d->listView, top, b ); + + ProtocolCheckListItem * last = 0; + for ( int i = 0 ; const char * name = b->enumerateProtocols( i ) ; ++i ) { + const CryptoBackend::Protocol * protocol = b->protocol( name ); + + if ( protocol ) { + last = new ProtocolCheckListItem( top, last, name, protocol ); + last->setOn( protocol == d->backendFactory->protocol( name ) ); + } else if ( b->supportsProtocol( name ) ) { + last = new ProtocolCheckListItem( top, last, name, 0 ); + last->setOn( false ); + last->setEnabled( false ); + } + } + + top->setOpen( true ); + ++backendCount; + } + + if ( backendCount ) { + d->listView->setCurrentItem( d->listView->firstChild() ); + d->listView->setSelected( d->listView->firstChild(), true ); + } + + slotSelectionChanged( d->listView->firstChild() ); +} + +void Kleo::BackendConfigWidget::slotSelectionChanged( QListViewItem * ) { + const CryptoBackend* backend = d->listView->currentBackend(); + if ( backend && !backend->config() ) + kdDebug(5150) << "Backend w/o config object!" << endl; + d->configureButton->setEnabled( backend && backend->config() ); +} + + +void Kleo::BackendConfigWidget::slotRescanButtonClicked() { + QStringList reasons; + d->backendFactory->scanForBackends( &reasons ); + if ( !reasons.empty() ) + KMessageBox::informationList( this, + i18n("The following problems where encountered during scanning:"), + reasons, i18n("Scan Results") ); + load(); + emit changed( true ); +} + +void Kleo::BackendConfigWidget::slotConfigureButtonClicked() { + const CryptoBackend* backend = d->listView->currentBackend(); + if ( backend && backend->config() ) { + Kleo::CryptoConfigDialog dlg( backend->config(), this ); + int result = dlg.exec(); + if ( result == QDialog::Accepted ) { + // Tell other users of gpgconf (e.g. the s/mime page) that the gpgconf data might have changed + kapp->dcopClient()->emitDCOPSignal( "KPIM::CryptoConfig", "changed()", QByteArray() ); + // and schedule a rescan, in case the updates make a backend valid + QTimer::singleShot( 0, this, SLOT(slotRescanButtonClicked()) ); + } + } + else // shouldn't happen, button is disabled + kdWarning(5150) << "Can't configure backend, no config object available" << endl; +} + +void Kleo::BackendConfigWidget::save() const { + for ( int i = 0 ; const char * name = d->backendFactory->enumerateProtocols( i ) ; ++i ) + d->backendFactory->setProtocolBackend( name, d->listView->chosenBackend( name ) ); +} + +void Kleo::BackendConfigWidget::virtual_hook( int, void* ) {} + +#include "backendconfigwidget.moc" diff --git a/certmanager/lib/ui/backendconfigwidget.h b/certmanager/lib/ui/backendconfigwidget.h new file mode 100644 index 000000000..0e26655ce --- /dev/null +++ b/certmanager/lib/ui/backendconfigwidget.h @@ -0,0 +1,76 @@ +/* -*- c++ -*- + backendconfigwidget.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2002,2004 Klarälvdalens Datakonsult AB + Copyright (c) 2002,2003 Marc Mutz <mutz@kde.org> + + Libkleopatra 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. + + Libkleopatra 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. + */ + +#ifndef __KLEO_UI_BACKENDCONFIGWIDGET_H__ +#define __KLEO_UI_BACKENDCONFIGWIDGET_H__ + +#include <qwidget.h> +#include <kdepimmacros.h> + +namespace Kleo { + class CryptoBackendFactory; +} + +class QListViewItem; + +namespace Kleo { + + class KDE_EXPORT BackendConfigWidget : public QWidget { + Q_OBJECT + public: + BackendConfigWidget( CryptoBackendFactory * factory, QWidget * parent=0, const char * name=0, WFlags f=0 ); + ~BackendConfigWidget(); + + void load(); + void save() const; + + void emitChanged( bool b ) { emit changed( b ); } + + signals: + void changed( bool ); + + private slots: + void slotSelectionChanged( QListViewItem * ); + void slotRescanButtonClicked(); + void slotConfigureButtonClicked(); + + private: + class Private; + Private * d; + protected: + virtual void virtual_hook( int, void* ); + }; + +} + +#endif // __KLEO_UI_BACKENDCONFIGWIDGET_H__ diff --git a/certmanager/lib/ui/cryptoconfigdialog.cpp b/certmanager/lib/ui/cryptoconfigdialog.cpp new file mode 100644 index 000000000..3fa0a97ca --- /dev/null +++ b/certmanager/lib/ui/cryptoconfigdialog.cpp @@ -0,0 +1,89 @@ +/* + cryptoconfigdialog.h + + This file is part of kgpgcertmanager + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + Libkleopatra 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 "cryptoconfigdialog.h" +#include "cryptoconfigmodule.h" +#include <klocale.h> +#include <kaccelmanager.h> + +Kleo::CryptoConfigDialog::CryptoConfigDialog( Kleo::CryptoConfig* config, QWidget *parent, const char* name ) + : KDialogBase( Swallow, + // Remove the "whats's this" button since we have no support for it + WStyle_Customize | WStyle_DialogBorder | WStyle_Maximize | WStyle_Title | WStyle_SysMenu, + parent, name, true /*modal*/, + i18n( "Configure" ), Default|Cancel|Apply|Ok|User1, + Ok, true /*separator*/, KGuiItem( i18n( "&Reset" ), "undo" ) ) +{ + mMainWidget = new CryptoConfigModule( config, this ); + setMainWidget( mMainWidget ); + connect( mMainWidget, SIGNAL( changed() ), SLOT( slotChanged() ) ); + enableButton( Apply, false ); + + // Automatically assign accelerators + KAcceleratorManager::manage( this ); +} + +void Kleo::CryptoConfigDialog::slotOk() +{ + slotApply(); + accept(); +} + +void Kleo::CryptoConfigDialog::slotCancel() +{ + mMainWidget->cancel(); + reject(); +} + +void Kleo::CryptoConfigDialog::slotDefault() +{ + mMainWidget->defaults(); + slotChanged(); +} + +void Kleo::CryptoConfigDialog::slotApply() +{ + mMainWidget->save(); + enableButton( Apply, false ); +} + +void Kleo::CryptoConfigDialog::slotUser1() // reset +{ + mMainWidget->reset(); + enableButton( Apply, false ); +} + +void Kleo::CryptoConfigDialog::slotChanged() +{ + enableButton( Apply, true ); +} + +#include "cryptoconfigdialog.moc" diff --git a/certmanager/lib/ui/cryptoconfigdialog.h b/certmanager/lib/ui/cryptoconfigdialog.h new file mode 100644 index 000000000..484c55ea4 --- /dev/null +++ b/certmanager/lib/ui/cryptoconfigdialog.h @@ -0,0 +1,69 @@ +/* + cryptoconfigdialog.h + + This file is part of kgpgcertmanager + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + Libkleopatra 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. +*/ + +#ifndef CRYPTOCONFIGDIALOG_H +#define CRYPTOCONFIGDIALOG_H + +#include <kdialogbase.h> +#include <kdepimmacros.h> + +namespace Kleo { + + class CryptoConfig; + class CryptoConfigModule; + + /** + * Simple KDialogBase wrapper around CryptoConfigModule + */ + class KDE_EXPORT CryptoConfigDialog : public KDialogBase + { + Q_OBJECT + public: + CryptoConfigDialog( Kleo::CryptoConfig* config, QWidget *parent = 0, const char* name = 0 ); + + protected: + virtual void slotOk(); + virtual void slotCancel(); + virtual void slotDefault(); + virtual void slotApply(); + virtual void slotUser1(); // reset + + public slots: + void slotChanged(); + + private: + CryptoConfigModule* mMainWidget; + }; + +} + +#endif /* CRYPTOCONFIGDIALOG_H */ + diff --git a/certmanager/lib/ui/cryptoconfigmodule.cpp b/certmanager/lib/ui/cryptoconfigmodule.cpp new file mode 100644 index 000000000..dbc8edc57 --- /dev/null +++ b/certmanager/lib/ui/cryptoconfigmodule.cpp @@ -0,0 +1,634 @@ +/* + cryptoconfigmodule.cpp + + This file is part of kgpgcertmanager + Copyright (c) 2004 Klar�vdalens Datakonsult AB + + Libkleopatra is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + Libkleopatra 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 "cryptoconfigmodule.h" +#include "cryptoconfigmodule_p.h" +#include "directoryserviceswidget.h" +#include "kdhorizontalline.h" + +#include <kleo/cryptoconfig.h> + +#include <klineedit.h> +#include <klocale.h> +#include <kdialogbase.h> +#include <kdebug.h> +#include <knuminput.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kurlrequester.h> + +#include <qgrid.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qvbox.h> +#include <qhbox.h> +#include <qpushbutton.h> +#include <qregexp.h> +#include <qstyle.h> +#include <qapplication.h> + +using namespace Kleo; + +static inline QPixmap loadIcon( QString s ) { + return KGlobal::instance()->iconLoader() + ->loadIcon( s.replace( QRegExp( "[^a-zA-Z0-9_]" ), "_" ), KIcon::NoGroup, KIcon::SizeMedium ); +} + +static const KJanusWidget::Face determineJanusFace( const Kleo::CryptoConfig * config ) { + return config && config->componentList().size() < 2 + ? KJanusWidget::Plain + : KJanusWidget::IconList ; +} + +Kleo::CryptoConfigModule::CryptoConfigModule( Kleo::CryptoConfig* config, QWidget * parent, const char * name ) + : KJanusWidget( parent, name, determineJanusFace( config ) ), mConfig( config ) +{ + QWidget * vbox = 0; + if ( face() == Plain ) { + vbox = plainPage(); + QVBoxLayout * vlay = new QVBoxLayout( vbox, 0, KDialog::spacingHint() ); + vlay->setAutoAdd( true ); + } + + const QStringList components = config->componentList(); + for ( QStringList::const_iterator it = components.begin(); it != components.end(); ++it ) { + //kdDebug(5150) << "Component " << (*it).local8Bit() << ":" << endl; + Kleo::CryptoConfigComponent* comp = config->component( *it ); + Q_ASSERT( comp ); + if ( comp->groupList().empty() ) + continue; + if ( face() != Plain ) { + vbox = addVBoxPage( comp->description(), QString::null, loadIcon( comp->iconName() ) ); + } + + QScrollView * scrollView = new QScrollView( vbox ); + scrollView->setHScrollBarMode( QScrollView::AlwaysOff ); + scrollView->setResizePolicy( QScrollView::AutoOneFit ); + QVBox* boxInScrollView = new QVBox( scrollView->viewport() ); + boxInScrollView->setMargin( KDialog::marginHint() ); + scrollView->addChild( boxInScrollView ); + + CryptoConfigComponentGUI* compGUI = + new CryptoConfigComponentGUI( this, comp, boxInScrollView, (*it).local8Bit() ); + // KJanusWidget doesn't seem to have iterators, so we store a copy... + mComponentGUIs.append( compGUI ); + + // Set a nice startup size + const int deskHeight = QApplication::desktop()->height(); + int dialogHeight; + if (deskHeight > 1000) // very big desktop ? + dialogHeight = 800; + else if (deskHeight > 650) // big desktop ? + dialogHeight = 500; + else // small (800x600, 640x480) desktop + dialogHeight = 400; + QSize sz = scrollView->sizeHint(); + scrollView->setMinimumSize( sz.width() + + scrollView->style().pixelMetric(QStyle::PM_ScrollBarExtent), + QMIN( compGUI->sizeHint().height(), dialogHeight ) ); + } +} + +void Kleo::CryptoConfigModule::save() +{ + bool changed = false; + QValueList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin(); + for( ; it != mComponentGUIs.end(); ++it ) { + if ( (*it)->save() ) + changed = true; + } + if ( changed ) + mConfig->sync(true /*runtime*/); +} + +void Kleo::CryptoConfigModule::reset() +{ + QValueList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin(); + for( ; it != mComponentGUIs.end(); ++it ) { + (*it)->load(); + } +} + +void Kleo::CryptoConfigModule::defaults() +{ + QValueList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin(); + for( ; it != mComponentGUIs.end(); ++it ) { + (*it)->defaults(); + } +} + +void Kleo::CryptoConfigModule::cancel() +{ + mConfig->clear(); +} + +//// + +Kleo::CryptoConfigComponentGUI::CryptoConfigComponentGUI( + CryptoConfigModule* module, Kleo::CryptoConfigComponent* component, + QWidget* parent, const char* name ) + : QWidget( parent, name ), + mComponent( component ) +{ + QGridLayout * glay = new QGridLayout( this, 1, 3, 0, KDialog::spacingHint() ); + const QStringList groups = mComponent->groupList(); + if ( groups.size() > 1 ) { + glay->setColSpacing( 0, KDHorizontalLine::indentHint() ); + for ( QStringList::const_iterator it = groups.begin(), end = groups.end() ; it != end; ++it ) { + Kleo::CryptoConfigGroup* group = mComponent->group( *it ); + Q_ASSERT( group ); + if ( !group ) + continue; + KDHorizontalLine * hl = new KDHorizontalLine( group->description(), this ); + const int row = glay->numRows(); + glay->addMultiCellWidget( hl, row, row, 0, 2 ); + mGroupGUIs.append( new CryptoConfigGroupGUI( module, group, glay, this ) ); + } + } else if ( !groups.empty() ) { + mGroupGUIs.append( new CryptoConfigGroupGUI( module, mComponent->group( groups.front() ), glay, this ) ); + } + glay->setRowStretch( glay->numRows(), 1 ); +} + + +bool Kleo::CryptoConfigComponentGUI::save() +{ + bool changed = false; + QValueList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin(); + for( ; it != mGroupGUIs.end(); ++it ) { + if ( (*it)->save() ) + changed = true; + } + return changed; +} + +void Kleo::CryptoConfigComponentGUI::load() +{ + QValueList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin(); + for( ; it != mGroupGUIs.end(); ++it ) + (*it)->load(); +} + +void Kleo::CryptoConfigComponentGUI::defaults() +{ + QValueList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin(); + for( ; it != mGroupGUIs.end(); ++it ) + (*it)->defaults(); +} + +//// + +Kleo::CryptoConfigGroupGUI::CryptoConfigGroupGUI( + CryptoConfigModule* module, Kleo::CryptoConfigGroup* group, + QGridLayout * glay, QWidget* widget, const char* name ) + : QObject( module, name ), mGroup( group ) +{ + const int startRow = glay->numRows(); + const QStringList entries = mGroup->entryList(); + for( QStringList::const_iterator it = entries.begin(), end = entries.end() ; it != end; ++it ) { + Kleo::CryptoConfigEntry* entry = group->entry( *it ); + Q_ASSERT( entry ); + if ( entry->level() > CryptoConfigEntry::Level_Advanced ) continue; + CryptoConfigEntryGUI* entryGUI = + CryptoConfigEntryGUIFactory::createEntryGUI( module, entry, *it, glay, widget ); + if ( entryGUI ) { + mEntryGUIs.append( entryGUI ); + entryGUI->load(); + } + } + const int endRow = glay->numRows() - 1; + if ( endRow < startRow ) + return; + + const QString iconName = group->iconName(); + if ( iconName.isEmpty() ) + return; + + QLabel * l = new QLabel( widget ); + l->setPixmap( loadIcon( iconName ) ); + glay->addMultiCellWidget( l, startRow, endRow, 0, 0, Qt::AlignTop ); +} + +bool Kleo::CryptoConfigGroupGUI::save() +{ + bool changed = false; + QValueList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin(); + for( ; it != mEntryGUIs.end(); ++it ) { + if ( (*it)->isChanged() ) { + (*it)->save(); + changed = true; + } + } + return changed; +} + +void Kleo::CryptoConfigGroupGUI::load() +{ + QValueList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin(); + for( ; it != mEntryGUIs.end(); ++it ) + (*it)->load(); +} + +void Kleo::CryptoConfigGroupGUI::defaults() +{ + QValueList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin(); + for( ; it != mEntryGUIs.end(); ++it ) + (*it)->resetToDefault(); +} + +//// + +CryptoConfigEntryGUI* Kleo::CryptoConfigEntryGUIFactory::createEntryGUI( CryptoConfigModule* module, Kleo::CryptoConfigEntry* entry, const QString& entryName, QGridLayout * glay, QWidget* widget, const char* name ) +{ + if ( entry->isList() ) { + switch( entry->argType() ) { + case Kleo::CryptoConfigEntry::ArgType_None: + // A list of options with no arguments (e.g. -v -v -v) is shown as a spinbox + return new CryptoConfigEntrySpinBox( module, entry, entryName, glay, widget, name ); + case Kleo::CryptoConfigEntry::ArgType_Int: + case Kleo::CryptoConfigEntry::ArgType_UInt: + // Let people type list of numbers (1,2,3....). Untested. + return new CryptoConfigEntryLineEdit( module, entry, entryName, glay, widget, name ); + case Kleo::CryptoConfigEntry::ArgType_URL: + case Kleo::CryptoConfigEntry::ArgType_Path: + case Kleo::CryptoConfigEntry::ArgType_DirPath: + case Kleo::CryptoConfigEntry::ArgType_String: + kdWarning(5150) << "No widget implemented for list of type " << entry->argType() << endl; + return 0; // TODO when the need arises :) + case Kleo::CryptoConfigEntry::ArgType_LDAPURL: + return new CryptoConfigEntryLDAPURL( module, entry, entryName, glay, widget, name ); + } + kdWarning(5150) << "No widget implemented for list of (unknown) type " << entry->argType() << endl; + return 0; + } + + switch( entry->argType() ) { + case Kleo::CryptoConfigEntry::ArgType_None: + return new CryptoConfigEntryCheckBox( module, entry, entryName, glay, widget, name ); + case Kleo::CryptoConfigEntry::ArgType_Int: + case Kleo::CryptoConfigEntry::ArgType_UInt: + return new CryptoConfigEntrySpinBox( module, entry, entryName, glay, widget, name ); + case Kleo::CryptoConfigEntry::ArgType_URL: + return new CryptoConfigEntryURL( module, entry, entryName, glay, widget, name ); + case Kleo::CryptoConfigEntry::ArgType_Path: + return new CryptoConfigEntryPath( module, entry, entryName, glay, widget, name ); + case Kleo::CryptoConfigEntry::ArgType_DirPath: + return new CryptoConfigEntryDirPath( module, entry, entryName, glay, widget, name ); + case Kleo::CryptoConfigEntry::ArgType_LDAPURL: + kdWarning(5150) << "No widget implemented for type " << entry->argType() << endl; + return 0; // TODO when the need arises :) + case Kleo::CryptoConfigEntry::ArgType_String: + return new CryptoConfigEntryLineEdit( module, entry, entryName, glay, widget, name ); + } + kdWarning(5150) << "No widget implemented for (unknown) type " << entry->argType() << endl; + return 0; +} + +//// + +Kleo::CryptoConfigEntryGUI::CryptoConfigEntryGUI( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + const char* name ) + : QObject( module, name ), mEntry( entry ), mName( entryName ), mChanged( false ) +{ + connect( this, SIGNAL( changed() ), module, SIGNAL( changed() ) ); +} + +QString Kleo::CryptoConfigEntryGUI::description() const +{ + QString descr = mEntry->description(); + if ( descr.isEmpty() ) // shouldn't happen + descr = QString( "<%1>" ).arg( mName ); + return descr; +} + +void Kleo::CryptoConfigEntryGUI::resetToDefault() +{ + mEntry->resetToDefault(); + load(); +} + +//// + +Kleo::CryptoConfigEntryLineEdit::CryptoConfigEntryLineEdit( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, const QString& entryName, + QGridLayout * glay, QWidget* widget, const char* name ) + : CryptoConfigEntryGUI( module, entry, entryName, name ) +{ + const int row = glay->numRows(); + mLineEdit = new KLineEdit( widget ); + QLabel* label = new QLabel( mLineEdit, description(), widget ); + glay->addWidget( label, row, 1 ); + glay->addWidget( mLineEdit, row, 2 ); + if ( entry->isReadOnly() ) { + label->setEnabled( false ); + mLineEdit->setEnabled( false ); + } else { + connect( mLineEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotChanged() ) ); + } +} + +void Kleo::CryptoConfigEntryLineEdit::doSave() +{ + mEntry->setStringValue( mLineEdit->text() ); +} + +void Kleo::CryptoConfigEntryLineEdit::doLoad() +{ + mLineEdit->setText( mEntry->stringValue() ); +} + +//// + +Kleo::CryptoConfigEntryPath::CryptoConfigEntryPath( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, const QString& entryName, + QGridLayout * glay, QWidget* widget, const char* name ) + : CryptoConfigEntryGUI( module, entry, entryName, name ) +{ + const int row = glay->numRows(); + mUrlRequester = new KURLRequester( widget ); + mUrlRequester->setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly ); + QLabel* label = new QLabel( mUrlRequester, description(), widget ); + glay->addWidget( label, row, 1 ); + glay->addWidget( mUrlRequester, row, 2 ); + if ( entry->isReadOnly() ) { + label->setEnabled( false ); + mUrlRequester->setEnabled( false ); + } else { + connect( mUrlRequester, SIGNAL( textChanged( const QString& ) ), SLOT( slotChanged() ) ); + } +} + +void Kleo::CryptoConfigEntryPath::doSave() +{ + KURL url; + url.setPath( mUrlRequester->url() ); + mEntry->setURLValue( url ); +} + +void Kleo::CryptoConfigEntryPath::doLoad() +{ + mUrlRequester->setURL( mEntry->urlValue().path() ); +} + +//// + +Kleo::CryptoConfigEntryDirPath::CryptoConfigEntryDirPath( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, const QString& entryName, + QGridLayout * glay, QWidget* widget, const char* name ) + : CryptoConfigEntryGUI( module, entry, entryName, name ) +{ + const int row = glay->numRows(); + mUrlRequester = new KURLRequester( widget ); + mUrlRequester->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly ); + QLabel* label = new QLabel( mUrlRequester, description(), widget ); + glay->addWidget( label, row, 1 ); + glay->addWidget( mUrlRequester, row, 2 ); + if ( entry->isReadOnly() ) { + label->setEnabled( false ); + mUrlRequester->setEnabled( false ); + } else { + connect( mUrlRequester, SIGNAL( textChanged( const QString& ) ), SLOT( slotChanged() ) ); + } +} + +void Kleo::CryptoConfigEntryDirPath::doSave() +{ + KURL url; + url.setPath( mUrlRequester->url() ); + mEntry->setURLValue( url ); + +} + +void Kleo::CryptoConfigEntryDirPath::doLoad() +{ + mUrlRequester->setURL( mEntry->urlValue().path() ); +} + +//// + +Kleo::CryptoConfigEntryURL::CryptoConfigEntryURL( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, const QString& entryName, + QGridLayout * glay, QWidget* widget, const char* name ) + : CryptoConfigEntryGUI( module, entry, entryName, name ) +{ + const int row = glay->numRows(); + mUrlRequester = new KURLRequester( widget ); + mUrlRequester->setMode( KFile::File | KFile::ExistingOnly ); + QLabel* label = new QLabel( mUrlRequester, description(), widget ); + glay->addWidget( label, row, 1 ); + glay->addWidget( mUrlRequester, row, 2 ); + if ( entry->isReadOnly() ) { + label->setEnabled( false ); + mUrlRequester->setEnabled( false ); + } else { + connect( mUrlRequester, SIGNAL( textChanged( const QString& ) ), SLOT( slotChanged() ) ); + } +} + +void Kleo::CryptoConfigEntryURL::doSave() +{ + mEntry->setURLValue( mUrlRequester->url() ); +} + +void Kleo::CryptoConfigEntryURL::doLoad() +{ + mUrlRequester->setURL( mEntry->urlValue().url() ); +} + +//// + +Kleo::CryptoConfigEntrySpinBox::CryptoConfigEntrySpinBox( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, const QString& entryName, + QGridLayout * glay, QWidget* widget, const char* name ) + : CryptoConfigEntryGUI( module, entry, entryName, name ) +{ + + if ( entry->argType() == Kleo::CryptoConfigEntry::ArgType_None && entry->isList() ) { + mKind = ListOfNone; + } else if ( entry->argType() == Kleo::CryptoConfigEntry::ArgType_UInt ) { + mKind = UInt; + } else { + Q_ASSERT( entry->argType() == Kleo::CryptoConfigEntry::ArgType_Int ); + mKind = Int; + } + + const int row = glay->numRows(); + mNumInput = new KIntNumInput( widget ); + QLabel* label = new QLabel( mNumInput, description(), widget ); + glay->addWidget( label, row, 1 ); + glay->addWidget( mNumInput, row, 2 ); + + if ( entry->isReadOnly() ) { + label->setEnabled( false ); + mNumInput->setEnabled( false ); + } else { + if ( mKind == UInt || mKind == ListOfNone ) + mNumInput->setMinValue( 0 ); + connect( mNumInput, SIGNAL( valueChanged(int) ), SLOT( slotChanged() ) ); + } +} + +void Kleo::CryptoConfigEntrySpinBox::doSave() +{ + int value = mNumInput->value(); + switch ( mKind ) { + case ListOfNone: + mEntry->setNumberOfTimesSet( value ); + break; + case UInt: + mEntry->setUIntValue( value ); + break; + case Int: + mEntry->setIntValue( value ); + break; + } +} + +void Kleo::CryptoConfigEntrySpinBox::doLoad() +{ + int value = 0; + switch ( mKind ) { + case ListOfNone: + value = mEntry->numberOfTimesSet(); + break; + case UInt: + value = mEntry->uintValue(); + break; + case Int: + value = mEntry->intValue(); + break; + } + mNumInput->setValue( value ); +} + +//// + +Kleo::CryptoConfigEntryCheckBox::CryptoConfigEntryCheckBox( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, const QString& entryName, + QGridLayout * glay, QWidget* widget, const char* name ) + : CryptoConfigEntryGUI( module, entry, entryName, name ) +{ + const int row = glay->numRows(); + mCheckBox = new QCheckBox( widget ); + glay->addMultiCellWidget( mCheckBox, row, row, 1, 2 ); + mCheckBox->setText( description() ); + if ( entry->isReadOnly() ) { + mCheckBox->setEnabled( false ); + } else { + connect( mCheckBox, SIGNAL( toggled(bool) ), SLOT( slotChanged() ) ); + } +} + +void Kleo::CryptoConfigEntryCheckBox::doSave() +{ + mEntry->setBoolValue( mCheckBox->isChecked() ); +} + +void Kleo::CryptoConfigEntryCheckBox::doLoad() +{ + mCheckBox->setChecked( mEntry->boolValue() ); +} + +Kleo::CryptoConfigEntryLDAPURL::CryptoConfigEntryLDAPURL( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + QGridLayout * glay, QWidget* widget, const char* name ) + : CryptoConfigEntryGUI( module, entry, entryName, name ) +{ + mLabel = new QLabel( widget ); + mPushButton = new QPushButton( i18n( "Edit..." ), widget ); + + const int row = glay->numRows(); + glay->addWidget( new QLabel( mPushButton, description(), widget ), row, 1 ); + QHBoxLayout * hlay = new QHBoxLayout; + glay->addLayout( hlay, row, 2 ); + hlay->addWidget( mLabel, 1 ); + hlay->addWidget( mPushButton ); + + if ( entry->isReadOnly() ) { + mLabel->setEnabled( false ); + mPushButton->hide(); + } else { + connect( mPushButton, SIGNAL( clicked() ), SLOT( slotOpenDialog() ) ); + } +} + +void Kleo::CryptoConfigEntryLDAPURL::doLoad() +{ + setURLList( mEntry->urlValueList() ); +} + +void Kleo::CryptoConfigEntryLDAPURL::doSave() +{ + mEntry->setURLValueList( mURLList ); +} + +void Kleo::CryptoConfigEntryLDAPURL::slotOpenDialog() +{ + // I'm a bad boy and I do it all on the stack. Enough classes already :) + // This is just a simple dialog around the directory-services-widget + KDialogBase dialog( mPushButton->parentWidget(), 0, true /*modal*/, + i18n( "Configure LDAP Servers" ), + KDialogBase::Default|KDialogBase::Cancel|KDialogBase::Ok, + KDialogBase::Ok, true /*separator*/ ); + DirectoryServicesWidget* dirserv = new DirectoryServicesWidget( mEntry, &dialog ); + dirserv->load(); + dialog.setMainWidget( dirserv ); + connect( &dialog, SIGNAL( defaultClicked() ), dirserv, SLOT( defaults() ) ); + if ( dialog.exec() ) { + // Note that we just grab the urls from the dialog, we don't call its save method, + // since the user hasn't confirmed the big config dialog yet. + setURLList( dirserv->urlList() ); + slotChanged(); + } +} + +void Kleo::CryptoConfigEntryLDAPURL::setURLList( const KURL::List& urlList ) +{ + mURLList = urlList; + if ( mURLList.isEmpty() ) + mLabel->setText( i18n( "No server configured yet" ) ); + else + mLabel->setText( i18n( "1 server configured", "%n servers configured", mURLList.count() ) ); +} + +#include "cryptoconfigmodule.moc" +#include "cryptoconfigmodule_p.moc" diff --git a/certmanager/lib/ui/cryptoconfigmodule.h b/certmanager/lib/ui/cryptoconfigmodule.h new file mode 100644 index 000000000..185814594 --- /dev/null +++ b/certmanager/lib/ui/cryptoconfigmodule.h @@ -0,0 +1,68 @@ +/* + cryptoconfigmodule.h + + This file is part of libkleopatra + Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB + + Libkleopatra is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + Libkleopatra 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. +*/ + +#ifndef CRYPTOCONFIGMODULE_H +#define CRYPTOCONFIGMODULE_H + +#include <kjanuswidget.h> + +#include <qvaluelist.h> + +namespace Kleo { + + class CryptoConfig; + class CryptoConfigComponentGUI; + + /** + * Crypto Config Module widget, dynamically generated from CryptoConfig + * It's a simple QWidget so that it can be embedded into a dialog or into a KCModule. + */ + class CryptoConfigModule : public KJanusWidget { + Q_OBJECT + public: + CryptoConfigModule( Kleo::CryptoConfig* config, QWidget * parent=0, const char * name=0 ); + + void save(); + void reset(); // i.e. reload current settings, discarding user input + void defaults(); + void cancel(); + + signals: + void changed(); + + private: + Kleo::CryptoConfig* mConfig; + QValueList<CryptoConfigComponentGUI *> mComponentGUIs; + }; + +} + +#endif diff --git a/certmanager/lib/ui/cryptoconfigmodule_p.h b/certmanager/lib/ui/cryptoconfigmodule_p.h new file mode 100644 index 000000000..22145f323 --- /dev/null +++ b/certmanager/lib/ui/cryptoconfigmodule_p.h @@ -0,0 +1,280 @@ +/* + cryptoconfigmodule_p.h + + This file is part of libkleopatra + Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB + + Libkleopatra is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + Libkleopatra 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. +*/ + +#ifndef CRYPTOCONFIGMODULE_P_H +#define CRYPTOCONFIGMODULE_P_H + +#include <qtabwidget.h> +#include <qhbox.h> +#include <qcheckbox.h> +#include <kurl.h> + +class KLineEdit; +class KIntNumInput; +class KURLRequester; +class QPushButton; +class QGridLayout; + +namespace Kleo { + + class CryptoConfig; + class CryptoConfigComponent; + class CryptoConfigGroup; + class CryptoConfigEntry; + class CryptoConfigComponentGUI; + class CryptoConfigGroupGUI; + class CryptoConfigEntryGUI; + + /** + * A widget corresponding to a component in the crypto config + */ + class CryptoConfigComponentGUI : public QWidget { + Q_OBJECT + + public: + CryptoConfigComponentGUI( CryptoConfigModule* module, Kleo::CryptoConfigComponent* component, + QWidget* parent, const char* name = 0 ); + + bool save(); + void load(); + void defaults(); + + private: + Kleo::CryptoConfigComponent* mComponent; + QValueList<CryptoConfigGroupGUI *> mGroupGUIs; + }; + + /** + * A class managing widgets corresponding to a group in the crypto config + */ + class CryptoConfigGroupGUI : public QObject { + Q_OBJECT + + public: + CryptoConfigGroupGUI( CryptoConfigModule* module, Kleo::CryptoConfigGroup* group, + QGridLayout * layout, QWidget* parent, const char* name = 0 ); + + bool save(); + void load(); + void defaults(); + + private: + Kleo::CryptoConfigGroup* mGroup; + QValueList<CryptoConfigEntryGUI *> mEntryGUIs; + }; + + /** + * Factory for CryptoConfigEntryGUI instances + * Not a real factory, but can become one later. + */ + class CryptoConfigEntryGUIFactory { + public: + static CryptoConfigEntryGUI* createEntryGUI( + CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, const QString& entryName, + QGridLayout * layout, QWidget* widget, const char* name = 0 ); + }; + + /** + * Base class for the widget managers tied to an entry in the crypto config + */ + class CryptoConfigEntryGUI : public QObject { + Q_OBJECT + public: + CryptoConfigEntryGUI( CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + const char* name = 0 ); + virtual ~CryptoConfigEntryGUI() {} + + void load() { doLoad(); mChanged = false; } + void save() { Q_ASSERT( mChanged ); doSave(); mChanged = false; } + void resetToDefault(); + + QString description() const; + bool isChanged() const { return mChanged; } + + signals: + void changed(); + + protected slots: + void slotChanged() { + mChanged = true; + emit changed(); + } + + protected: + virtual void doSave() = 0; + virtual void doLoad() = 0; + + Kleo::CryptoConfigEntry* mEntry; + QString mName; + bool mChanged; + }; + + /** + * A widget manager for a string entry in the crypto config + */ + class CryptoConfigEntryLineEdit : public CryptoConfigEntryGUI { + Q_OBJECT + + public: + CryptoConfigEntryLineEdit( CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + QGridLayout * layout, + QWidget* parent, const char* name = 0 ); + + virtual void doSave(); + virtual void doLoad(); + private: + KLineEdit* mLineEdit; + }; + + /** + * A widget manager for a path entry in the crypto config + */ + class CryptoConfigEntryPath : public CryptoConfigEntryGUI { + Q_OBJECT + + public: + CryptoConfigEntryPath( CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + QGridLayout * layout, + QWidget* parent, const char* name = 0 ); + + virtual void doSave(); + virtual void doLoad(); + private: + KURLRequester* mUrlRequester; + }; + + /** + * A widget manager for a directory path entry in the crypto config + */ + class CryptoConfigEntryDirPath : public CryptoConfigEntryGUI { + Q_OBJECT + + public: + CryptoConfigEntryDirPath( CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + QGridLayout * layout, + QWidget* parent, const char* name = 0 ); + + virtual void doSave(); + virtual void doLoad(); + private: + KURLRequester* mUrlRequester; + }; + + /** + * A widget manager for an URL entry in the crypto config + */ + class CryptoConfigEntryURL : public CryptoConfigEntryGUI { + Q_OBJECT + + public: + CryptoConfigEntryURL( CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + QGridLayout * layout, + QWidget* parent, const char* name = 0 ); + + virtual void doSave(); + virtual void doLoad(); + private: + KURLRequester * mUrlRequester; + }; + + /** + * A widget manager for an int/uint entry in the crypto config + */ + class CryptoConfigEntrySpinBox : public CryptoConfigEntryGUI { + Q_OBJECT + + public: + CryptoConfigEntrySpinBox( CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + QGridLayout * layout, + QWidget* parent, const char* name = 0 ); + virtual void doSave(); + virtual void doLoad(); + private: + enum { Int, UInt, ListOfNone } mKind; + KIntNumInput* mNumInput; + }; + + /** + * A widget manager for a bool entry in the crypto config + */ + class CryptoConfigEntryCheckBox : public CryptoConfigEntryGUI { + Q_OBJECT + + public: + CryptoConfigEntryCheckBox( CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + QGridLayout * layout, + QWidget* parent, const char* name = 0 ); + virtual void doSave(); + virtual void doLoad(); + private: + QCheckBox* mCheckBox; + }; + + /** + * A widget manager for a bool entry in the crypto config + */ + class CryptoConfigEntryLDAPURL : public CryptoConfigEntryGUI { + Q_OBJECT + + public: + CryptoConfigEntryLDAPURL( CryptoConfigModule* module, + Kleo::CryptoConfigEntry* entry, + const QString& entryName, + QGridLayout * layout, + QWidget* parent, const char* name = 0 ); + virtual void doSave(); + virtual void doLoad(); + private slots: + void slotOpenDialog(); + private: + void setURLList( const KURL::List& urlList ); + QLabel* mLabel; + QPushButton* mPushButton; + KURL::List mURLList; + }; +} + +#endif // CRYPTOCONFIGMODULE_P_H diff --git a/certmanager/lib/ui/directoryserviceswidget.cpp b/certmanager/lib/ui/directoryserviceswidget.cpp new file mode 100644 index 000000000..76c1b3dda --- /dev/null +++ b/certmanager/lib/ui/directoryserviceswidget.cpp @@ -0,0 +1,308 @@ +/* + directoryserviceswidget.cpp + + This file is part of Kleopatra, the KDE keymanager + Copyright (c) 2001,2002,2004 Klar�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 <config.h> + +#include "directoryserviceswidget.h" +#include "adddirectoryservicedialogimpl.h" +#include "cryptplugwrapper.h" + +#include <klineedit.h> +#include <kleo/cryptoconfig.h> +#include <kiconloader.h> +#include <kdebug.h> + +#include <qbuttongroup.h> +#include <qtoolbutton.h> +#include <qlistview.h> +#include <qpushbutton.h> + +using namespace Kleo; + +class QX500ListViewItem : public QListViewItem +{ +public: + QX500ListViewItem( QListView* lv, QListViewItem* prev, + const QString& serverName, + const QString& portNumber, + const QString& dn, + const QString& username, + const QString& password ) + : QListViewItem( lv, prev, serverName, portNumber, dn, username ) { + setPassword( password ); + } + + void setPassword( const QString& pass ) { + mPassword = pass; + setText( 4, pass.isEmpty() ? QString::null : QString::fromLatin1( "******" ) ); + } + + const QString& password() const { return mPassword; } + + void setData( const QString& serverName, + const QString& portNumber, + const QString& dn, + const QString& username, + const QString& password ) { + setText( 0, serverName ); + setText( 1, portNumber ); + setText( 2, dn ); + setText( 3, username ); + setPassword( password ); + } + + void copyItem( QX500ListViewItem* item ) { + for ( unsigned int i = 0; i < 4 ; ++i ) + setText( i, item->text( i ) ); + setPassword( item->password() ); + } + +private: + QString mPassword; +}; + +Kleo::DirectoryServicesWidget::DirectoryServicesWidget( + Kleo::CryptoConfigEntry* configEntry, + QWidget* parent, const char* name, WFlags fl ) + : DirectoryServicesWidgetBase( parent, name, fl ), + mConfigEntry( configEntry ) +{ + x500LV->setSorting( -1 ); + + // taken from kmail's configuredialog.cpp + upButton->setIconSet( BarIconSet( "up", KIcon::SizeSmall ) ); + upButton->setEnabled( false ); // b/c no item is selected yet + + downButton->setIconSet( BarIconSet( "down", KIcon::SizeSmall ) ); + downButton->setEnabled( false ); // b/c no item is selected yet +} + + +/* + * Destroys the object and frees any allocated resources + */ +DirectoryServicesWidget::~DirectoryServicesWidget() +{ + // no need to delete child widgets, Qt does it all for us +} + + +/** + Enables or disables the widgets in this dialog according to the + capabilities of the current plugin passed as a parameter. +*/ +void DirectoryServicesWidget::enableDisable( CryptPlugWrapper* cryptPlug ) // unused? +{ + // disable the whole page if the plugin does not support the use + // of directory services + setEnabled( cryptPlug->hasFeature( Feature_CertificateDirectoryService ) || + cryptPlug->hasFeature( Feature_CRLDirectoryService ) ); +} + + +/* + * protected slot, connected to selectionChanged() + */ +void DirectoryServicesWidget::slotServiceChanged( QListViewItem* item ) +{ + if( item ) + removeServicePB->setEnabled( true ); + else + removeServicePB->setEnabled( false ); + downButton->setEnabled( item && item->itemBelow() ); + upButton->setEnabled( item && item->itemAbove() ); +} + + +/* + * protected slot, connected to returnPressed/doubleClicked + */ +void DirectoryServicesWidget::slotServiceSelected( QListViewItem* item ) +{ + AddDirectoryServiceDialogImpl* dlg = new AddDirectoryServiceDialogImpl( this ); + dlg->serverNameED->setText( item->text( 0 ) ); + dlg->portED->setText( item->text( 1 ) ); + dlg->descriptionED->setText( item->text( 2 ) ); + dlg->usernameED->setText( item->text( 3 ) ); + QString pass = static_cast<QX500ListViewItem *>( item )->password(); + dlg->passwordED->setText( pass ); + + if( dlg->exec() == QDialog::Accepted ) { + item->setText( 0, dlg->serverNameED->text() ); + item->setText( 1, dlg->portED->text() ); + item->setText( 2, dlg->descriptionED->text() ); + item->setText( 3, dlg->usernameED->text() ); + static_cast<QX500ListViewItem *>( item )->setPassword( dlg->passwordED->text() ); + emit changed(); + } + delete dlg; +} + + +/* + * protected slot + */ +void DirectoryServicesWidget::slotAddService() +{ + AddDirectoryServiceDialogImpl* dlg = new AddDirectoryServiceDialogImpl( this ); + if( dlg->exec() == QDialog::Accepted ) { + QX500ListViewItem *item = new QX500ListViewItem( x500LV, x500LV->lastItem(), + dlg->serverNameED->text(), + dlg->portED->text(), + dlg->descriptionED->text(), + dlg->usernameED->text(), + dlg->passwordED->text() ); + slotServiceChanged(item); + emit changed(); + } + delete dlg; +} + +/* + * protected slot + */ +void DirectoryServicesWidget::slotDeleteService() +{ + QListViewItem* item = x500LV->selectedItem(); + Q_ASSERT( item ); + if( !item ) + return; + else + delete item; + x500LV->triggerUpdate(); + item = x500LV->currentItem(); + x500LV->setCurrentItem( item ); // seems necessary... + x500LV->setSelected( item, true ); + emit changed(); +} + + +void DirectoryServicesWidget::setInitialServices( const KURL::List& urls ) +{ + x500LV->clear(); + for( KURL::List::const_iterator it = urls.begin(); it != urls.end(); ++it ) { + QString dn = KURL::decode_string( (*it).query().mid( 1 ) ); // decode query and skip leading '?' + (void)new QX500ListViewItem( x500LV, x500LV->lastItem(), + (*it).host(), + QString::number( (*it).port() ), + dn, + (*it).user(), + (*it).pass()); + } +} + +KURL::List DirectoryServicesWidget::urlList() const +{ + KURL::List lst; + QListViewItemIterator it( x500LV ); + for ( ; it.current() ; ++it ) { + QListViewItem* item = it.current(); + KURL url; + url.setProtocol( "ldap" ); + url.setHost( item->text( 0 ) ); + url.setPort( item->text( 1 ).toInt() ); + url.setPath( "/" ); // workaround KURL parsing bug + url.setQuery( item->text( 2 ) ); + url.setUser( item->text( 3 ) ); + url.setPass( static_cast<QX500ListViewItem *>( item )->password() ); + kdDebug() << url << endl; + lst << url; + } + return lst; +} + +void DirectoryServicesWidget::clear() +{ + x500LV->clear(); + emit changed(); +} + +void DirectoryServicesWidget::load() +{ + if ( mConfigEntry ) { + setInitialServices( mConfigEntry->urlValueList() ); + } +} + +void DirectoryServicesWidget::save() +{ + if ( mConfigEntry ) { + mConfigEntry->setURLValueList( urlList() ); + } +} + +void DirectoryServicesWidget::defaults() +{ + if ( mConfigEntry ) { + // resetToDefault doesn't work since gpgconf doesn't know any defaults for this entry. + //mConfigEntry->resetToDefault(); + //load(); + clear(); // the default is an empty list. + } +} + +static void swapItems( QX500ListViewItem *item, QX500ListViewItem *other ) +{ + QString serverName = item->text( 0 ); + QString portNumber = item->text( 1 ); + QString dn = item->text( 2 ); + QString username = item->text( 3 ); + QString password = item->password(); + item->copyItem( other ); + other->setData( serverName, portNumber, dn, username, password ); +} + +void Kleo::DirectoryServicesWidget::slotMoveUp() +{ + QX500ListViewItem *item = static_cast<QX500ListViewItem *>( x500LV->selectedItem() ); + if ( !item ) return; + QX500ListViewItem *above = static_cast<QX500ListViewItem *>( item->itemAbove() ); + if ( !above ) return; + swapItems( item, above ); + x500LV->setCurrentItem( above ); + x500LV->setSelected( above, true ); + emit changed(); +} + +void Kleo::DirectoryServicesWidget::slotMoveDown() +{ + QX500ListViewItem *item = static_cast<QX500ListViewItem *>( x500LV->selectedItem() ); + if ( !item ) return; + QX500ListViewItem *below = static_cast<QX500ListViewItem *>( item->itemBelow() ); + if ( !below ) return; + swapItems( item, below ); + x500LV->setCurrentItem( below ); + x500LV->setSelected( below, true ); + emit changed(); +} + +#include "directoryserviceswidget.moc" diff --git a/certmanager/lib/ui/directoryserviceswidget.h b/certmanager/lib/ui/directoryserviceswidget.h new file mode 100644 index 000000000..02e428c95 --- /dev/null +++ b/certmanager/lib/ui/directoryserviceswidget.h @@ -0,0 +1,82 @@ +/* + directoryserviceswidget.h + + This file is part of Kleopatra, the KDE keymanager + Copyright (c) 2001,2002,2004 Klarälvdalens 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. +*/ + +#ifndef DIRECTORYSERVICESWIDGET_H +#define DIRECTORYSERVICESWIDGET_H +#include "directoryserviceswidgetbase.h" +#include <kurl.h> +#include <kdepimmacros.h> + +class CryptPlugWrapper; +namespace Kleo { + +class CryptoConfigEntry; + +class KDE_EXPORT DirectoryServicesWidget : public DirectoryServicesWidgetBase +{ + Q_OBJECT + +public: + DirectoryServicesWidget( + Kleo::CryptoConfigEntry* configEntry, + QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + ~DirectoryServicesWidget(); + + void load(); + void save(); + + void enableDisable( CryptPlugWrapper* wrapper ); // unused? + void setInitialServices( const KURL::List& urls ); + KURL::List urlList() const; + void clear(); + +public slots: + void defaults(); + +signals: + void changed(); + +protected slots: + void slotServiceChanged( QListViewItem* ); + void slotServiceSelected( QListViewItem* ); + void slotAddService(); + void slotDeleteService(); + void slotMoveUp(); + void slotMoveDown(); + +private: + Kleo::CryptoConfigEntry* mConfigEntry; +}; + +} + +#endif // DIRECTORYSERVICESWIDGET_H diff --git a/certmanager/lib/ui/directoryserviceswidgetbase.ui b/certmanager/lib/ui/directoryserviceswidgetbase.ui new file mode 100644 index 000000000..1dabbca51 --- /dev/null +++ b/certmanager/lib/ui/directoryserviceswidgetbase.ui @@ -0,0 +1,342 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>DirectoryServicesWidgetBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>DirectoryServicesWidgetBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>576</width> + <height>363</height> + </rect> + </property> + <property name="caption"> + <string>Directory Services Configuration</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>x500LA</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="text"> + <string>X.&500 directory services:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>x500LV</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <column> + <property name="text"> + <string>Server Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Port</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Base DN</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>User Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Password</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>x500LV</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Select Directory Services to Use Here</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt> +<h1>X.500 Directory Services</h1> +You can use X.500 directory services to retrieve certificates and certificate revocation lists that are not saved locally. Ask your local administrator if you want to make use of this feature and are unsure which directory service you can use. +<p> +If you do not use a directory service, you can still use local certificates. +</qt></string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QToolButton"> + <property name="name"> + <cstring>upButton</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>downButton</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>51</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>Spacer10</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>47</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>addServicePB</cstring> + </property> + <property name="text"> + <string>&Add Service...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Click to add a service</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt> +<h1>Add a Directory Service</h1> +By clicking this button, you can select a new directory service to be used for retrieving certificates and CRLs. You will be asked for the server name and an optional description. +</qt></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer11</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>47</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>removeServicePB</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Remove Service</string> + </property> + <property name="toolTip" stdset="0"> + <string>Click to remove the currently selected service</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt> +<h1>Remove Directory Service</h1> +By clicking this button, you can remove the currently selected directory service in the list above. You will have a chance to rethink your decision before the entry is deleted from the list. +</qt></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer12</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>47</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer9</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<connections> + <connection> + <sender>removeServicePB</sender> + <signal>clicked()</signal> + <receiver>DirectoryServicesWidgetBase</receiver> + <slot>slotDeleteService()</slot> + </connection> + <connection> + <sender>x500LV</sender> + <signal>returnPressed(QListViewItem*)</signal> + <receiver>DirectoryServicesWidgetBase</receiver> + <slot>slotServiceSelected(QListViewItem*)</slot> + </connection> + <connection> + <sender>x500LV</sender> + <signal>doubleClicked(QListViewItem*)</signal> + <receiver>DirectoryServicesWidgetBase</receiver> + <slot>slotServiceSelected(QListViewItem*)</slot> + </connection> + <connection> + <sender>x500LV</sender> + <signal>selectionChanged(QListViewItem*)</signal> + <receiver>DirectoryServicesWidgetBase</receiver> + <slot>slotServiceChanged(QListViewItem*)</slot> + </connection> + <connection> + <sender>addServicePB</sender> + <signal>clicked()</signal> + <receiver>DirectoryServicesWidgetBase</receiver> + <slot>slotAddService()</slot> + </connection> + <connection> + <sender>upButton</sender> + <signal>clicked()</signal> + <receiver>DirectoryServicesWidgetBase</receiver> + <slot>slotMoveUp()</slot> + </connection> + <connection> + <sender>downButton</sender> + <signal>clicked()</signal> + <receiver>DirectoryServicesWidgetBase</receiver> + <slot>slotMoveDown()</slot> + </connection> +</connections> +<slots> + <slot access="protected">slotAddService()</slot> + <slot access="protected">slotDeleteService()</slot> + <slot access="protected">slotServiceChanged( QListViewItem* )</slot> + <slot access="protected">slotServiceSelected( QListViewItem* )</slot> + <slot access="protected">slotMoveUp()</slot> + <slot access="protected">slotMoveDown()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/certmanager/lib/ui/dnattributeorderconfigwidget.cpp b/certmanager/lib/ui/dnattributeorderconfigwidget.cpp new file mode 100644 index 000000000..54fe32af1 --- /dev/null +++ b/certmanager/lib/ui/dnattributeorderconfigwidget.cpp @@ -0,0 +1,309 @@ +/* -*- c++ -*- + dnattributeorderconfigwidget.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klar�vdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "dnattributeorderconfigwidget.h" + +#include "kleo/dn.h" + +#include <klocale.h> +#include <kdebug.h> +#include <kdialog.h> +#include <kiconloader.h> +#include <kconfig.h> +#include <kapplication.h> + +#include <qtoolbutton.h> +#include <qlayout.h> +#include <qheader.h> +#include <qlabel.h> +#include <qlistview.h> +#include <qtooltip.h> + +#include <assert.h> + +struct Kleo::DNAttributeOrderConfigWidget::Private { + enum { UUp=0, Up=1, Left=2, Right=3, Down=4, DDown=5 }; + + QListView * availableLV; + QListView * currentLV; + QToolButton * navTB[6]; + + QListViewItem * placeHolderItem; + + Kleo::DNAttributeMapper * mapper; +}; + +static void prepare( QListView * lv ) { + lv->setAllColumnsShowFocus( true ); + lv->setResizeMode( QListView::LastColumn ); + lv->header()->setClickEnabled( false ); + lv->addColumn( QString::null ); + lv->addColumn( i18n("Description") ); +} + +Kleo::DNAttributeOrderConfigWidget::DNAttributeOrderConfigWidget( DNAttributeMapper * mapper, QWidget * parent, const char * name, WFlags f ) + : QWidget( parent, name, f ), d( 0 ) +{ + assert( mapper ); + d = new Private(); + d->mapper = mapper; + + QGridLayout * glay = new QGridLayout( this, 2, 3, 0, KDialog::spacingHint() ); + glay->setColStretch( 0, 1 ); + glay->setColStretch( 2, 1 ); + + int row = -1; + + ++row; + glay->addWidget( new QLabel( i18n("Available attributes:"), this ), row, 0 ); + glay->addWidget( new QLabel( i18n("Current attribute order:"), this ), row, 2 ); + + + ++row; + glay->setRowStretch( row, 1 ); + + d->availableLV = new QListView( this ); + prepare( d->availableLV ); + d->availableLV->setSorting( 0 ); + glay->addWidget( d->availableLV, row, 0 ); + + d->currentLV = new QListView( this ); + prepare( d->currentLV ); + d->currentLV->setSorting( -1 ); + glay->addWidget( d->currentLV, row, 2 ); + + connect( d->availableLV, SIGNAL(clicked( QListViewItem * )), + SLOT(slotAvailableSelectionChanged(QListViewItem*)) ); + connect( d->currentLV, SIGNAL(clicked(QListViewItem*)), + SLOT(slotCurrentOrderSelectionChanged(QListViewItem*)) ); + + d->placeHolderItem = new QListViewItem( d->availableLV, "_X_", i18n("All others") ); + + // the up/down/left/right arrow cross: + + QGridLayout * xlay = new QGridLayout( 5, 3, 0, "xlay" ); + xlay->setAlignment( AlignCenter ); + + static const struct { + const char * icon; + int row, col; + const char * tooltip; + const char * slot; + } navButtons[] = { + { "2uparrow", 0, 1, I18N_NOOP( "Move to top" ), SLOT(slotDoubleUpButtonClicked()) }, + { "1uparrow", 1, 1, I18N_NOOP( "Move one up" ), SLOT(slotUpButtonClicked()) }, + { "1leftarrow", 2, 0, I18N_NOOP( "Remove from current attribute order" ), SLOT(slotLeftButtonClicked()) }, + { "1rightarrow", 2, 2, I18N_NOOP( "Add to current attribute order" ), SLOT(slotRightButtonClicked()) }, + { "1downarrow", 3, 1, I18N_NOOP( "Move one down" ), SLOT(slotDownButtonClicked()) }, + { "2downarrow", 4, 1, I18N_NOOP( "Move to bottom" ), SLOT(slotDoubleDownButtonClicked()) } + }; + + for ( unsigned int i = 0 ; i < sizeof navButtons / sizeof *navButtons ; ++i ) { + QToolButton * tb = d->navTB[i] = new QToolButton( this ); + tb->setIconSet( SmallIconSet( navButtons[i].icon ) ); + tb->setEnabled( false ); + QToolTip::add( tb, i18n( navButtons[i].tooltip ) ); + xlay->addWidget( tb, navButtons[i].row, navButtons[i].col ); + connect( tb, SIGNAL(clicked()), navButtons[i].slot ); + } + + glay->addLayout( xlay, row, 1 ); +} + +Kleo::DNAttributeOrderConfigWidget::~DNAttributeOrderConfigWidget() { + delete d; d = 0; +} + +void Kleo::DNAttributeOrderConfigWidget::load() { + // save the _X_ item: + takePlaceHolderItem(); + // clear the rest: + d->availableLV->clear(); + d->currentLV->clear(); + + const QStringList order = d->mapper->attributeOrder(); + + // fill the RHS listview: + QListViewItem * last = 0; + for ( QStringList::const_iterator it = order.begin() ; it != order.end() ; ++it ) { + const QString attr = (*it).upper(); + if ( attr == "_X_" ) { + takePlaceHolderItem(); + d->currentLV->insertItem( d->placeHolderItem ); + d->placeHolderItem->moveItem( last ); + last = d->placeHolderItem; + } else + last = new QListViewItem( d->currentLV, last, attr, d->mapper->name2label( attr ) ); + } + + // fill the LHS listview with what's left: + + const QStringList all = Kleo::DNAttributeMapper::instance()->names(); + for ( QStringList::const_iterator it = all.begin() ; it != all.end() ; ++it ) + if ( order.find( *it ) == order.end() ) + (void)new QListViewItem( d->availableLV, *it, d->mapper->name2label( *it ) ); + + if ( !d->placeHolderItem->listView() ) + d->availableLV->insertItem( d->placeHolderItem ); +} + +void Kleo::DNAttributeOrderConfigWidget::takePlaceHolderItem() { + if ( QListView * lv = d->placeHolderItem->listView() ) + lv->takeItem( d->placeHolderItem ); +} + +void Kleo::DNAttributeOrderConfigWidget::save() const { + QStringList order; + for ( QListViewItemIterator it( d->currentLV ) ; it.current() ; ++it ) + order.push_back( it.current()->text( 0 ) ); + + d->mapper->setAttributeOrder( order ); +} + +void Kleo::DNAttributeOrderConfigWidget::defaults() { + kdDebug() << "Sorry, not implemented: Kleo::DNAttributeOrderConfigWidget::defaults()" << endl; +} + + + +void Kleo::DNAttributeOrderConfigWidget::slotAvailableSelectionChanged( QListViewItem * item ) { + d->navTB[Private::Right]->setEnabled( item ); +} + +void Kleo::DNAttributeOrderConfigWidget::slotCurrentOrderSelectionChanged( QListViewItem * item ) { + enableDisableButtons( item ); +} + +void Kleo::DNAttributeOrderConfigWidget::enableDisableButtons( QListViewItem * item ) { + d->navTB[Private::UUp ]->setEnabled( item && item->itemAbove() ); + d->navTB[Private::Up ]->setEnabled( item && item->itemAbove() ); + d->navTB[Private::Left ]->setEnabled( item ); + d->navTB[Private::Down ]->setEnabled( item && item->itemBelow() ); + d->navTB[Private::DDown]->setEnabled( item && item->itemBelow() ); +} + +void Kleo::DNAttributeOrderConfigWidget::slotUpButtonClicked() { + QListViewItem * item = d->currentLV->selectedItem(); + if ( !item ) + return; + QListViewItem * above = item->itemAbove(); + if ( !above ) + return; + above->moveItem( item ); // moves "above" to after "item", ie. "item" one up + enableDisableButtons( item ); + emit changed(); +} + +void Kleo::DNAttributeOrderConfigWidget::slotDoubleUpButtonClicked() { + QListViewItem * item = d->currentLV->selectedItem(); + if ( !item ) + return; + if ( item == d->currentLV->firstChild() ) + return; + d->currentLV->takeItem( item ); + d->currentLV->insertItem( item ); + d->currentLV->setSelected( item, true ); + enableDisableButtons( item ); + emit changed(); +} + +void Kleo::DNAttributeOrderConfigWidget::slotDownButtonClicked() { + QListViewItem * item = d->currentLV->selectedItem(); + if ( !item ) + return; + QListViewItem * below = item->itemBelow(); + if ( !below ) + return; + item->moveItem( below ); // moves "item" to after "below", ie. "item" one down + enableDisableButtons( item ); + emit changed(); +} + +void Kleo::DNAttributeOrderConfigWidget::slotDoubleDownButtonClicked() { + QListViewItem * item = d->currentLV->selectedItem(); + if ( !item ) + return; + QListViewItem * last = d->currentLV->lastItem(); + assert( last ); + if ( item == last ) + return; + item->moveItem( last ); // moves "item" to after "last", ie. to the bottom + enableDisableButtons( item ); + emit changed(); +} + +void Kleo::DNAttributeOrderConfigWidget::slotLeftButtonClicked() { + QListViewItem * right = d->currentLV->selectedItem(); + if ( !right ) + return; + QListViewItem * next = right->itemBelow(); + if ( !next ) + next = right->itemAbove(); + d->currentLV->takeItem( right ); + d->availableLV->insertItem( right ); + if ( next ) + d->currentLV->setSelected( next, true ); + enableDisableButtons( next ); + emit changed(); +} + +void Kleo::DNAttributeOrderConfigWidget::slotRightButtonClicked() { + QListViewItem * left = d->availableLV->selectedItem(); + if ( !left ) + return; + QListViewItem * next = left->itemBelow(); + if ( !next ) + next = left->itemAbove(); + d->availableLV->takeItem( left ); + d->currentLV->insertItem( left ); + if ( QListViewItem * right = d->currentLV->selectedItem() ) { + if ( QListViewItem * above = right->itemAbove() ) + left->moveItem( above ); // move new item immediately before old selected + d->currentLV->setSelected( right, false ); + } + d->currentLV->setSelected( left, true ); + enableDisableButtons( left ); + d->navTB[Private::Right]->setEnabled( next ); + if ( next ) + d->availableLV->setSelected( next, true ); + emit changed(); +} + + + +void Kleo::DNAttributeOrderConfigWidget::virtual_hook( int, void* ) {} + +#include "dnattributeorderconfigwidget.moc" diff --git a/certmanager/lib/ui/dnattributeorderconfigwidget.h b/certmanager/lib/ui/dnattributeorderconfigwidget.h new file mode 100644 index 000000000..11299ab37 --- /dev/null +++ b/certmanager/lib/ui/dnattributeorderconfigwidget.h @@ -0,0 +1,87 @@ +/* -*- c++ -*- + dnattributeorderconfigwidget.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. + */ + +#ifndef __KLEO_UI_DNATTRIBUTEORDERCONFIGWIDGET_H__ +#define __KLEO_UI_DNATTRIBUTEORDERCONFIGWIDGET_H__ + +#include <qwidget.h> +#include <kdepimmacros.h> +namespace Kleo { + class DNAttributeMapper; +} + +class QListViewItem; + +namespace Kleo { + + class KDE_EXPORT DNAttributeOrderConfigWidget : public QWidget { + Q_OBJECT + public: + /*! Use Kleo::DNAttributeMapper::instance()->configWidget( parent, name ) instead. */ + DNAttributeOrderConfigWidget( DNAttributeMapper * mapper, QWidget * parent=0, const char * name=0, WFlags f=0 ); + ~DNAttributeOrderConfigWidget(); + + void load(); + void save() const; + void defaults(); + + signals: + void changed(); + + // + // only boring stuff below... + // + + private slots: + void slotAvailableSelectionChanged( QListViewItem * ); + void slotCurrentOrderSelectionChanged( QListViewItem * ); + void slotDoubleUpButtonClicked(); + void slotUpButtonClicked(); + void slotDownButtonClicked(); + void slotDoubleDownButtonClicked(); + void slotLeftButtonClicked(); + void slotRightButtonClicked(); + + private: + void takePlaceHolderItem(); + void enableDisableButtons( QListViewItem * ); + + private: + class Private; + Private * d; + protected: + virtual void virtual_hook( int, void* ); + }; + +} + +#endif // __KLEO_UI_DNATTRIBUTEORDERCONFIGWIDGET_H__ diff --git a/certmanager/lib/ui/kdhorizontalline.cpp b/certmanager/lib/ui/kdhorizontalline.cpp new file mode 100644 index 000000000..83b92a19b --- /dev/null +++ b/certmanager/lib/ui/kdhorizontalline.cpp @@ -0,0 +1,171 @@ +/* -*- Mode: C++ -*- + KD Tools - a set of useful widgets for Qt +*/ + +/**************************************************************************** +** Copyright (C) 2005 Klarälvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.klaralvdalens-datakonsult.se/?page=products for +** information about KD Tools Commercial License Agreements. +** +** Contact info@klaralvdalens-datakonsult.se if any conditions of this +** licensing are not clear to you. +** +** 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 "kdhorizontalline.h" + +#include <qstyle.h> +#include <qpainter.h> +#ifdef QT_ACCESSIBILITY_SUPPORT +#include <qaccessible.h> +#endif +#include <qfontmetrics.h> +#include <qapplication.h> + +KDHorizontalLine::KDHorizontalLine( QWidget * parent, const char * name, WFlags f ) + : QFrame( parent, name, f ), + mAlign( Qt::AlignAuto ), + mLenVisible( 0 ) +{ + QFrame::setFrameStyle( HLine | Sunken ); +} + +KDHorizontalLine::KDHorizontalLine( const QString & title, QWidget * parent, const char * name, WFlags f ) + : QFrame( parent, name, f ), + mAlign( Qt::AlignAuto ), + mLenVisible( 0 ) +{ + QFrame::setFrameStyle( HLine | Sunken ); + setTitle( title ); +} + +KDHorizontalLine::~KDHorizontalLine() {} + +void KDHorizontalLine::setFrameStyle( int style ) { + QFrame::setFrameStyle( ( style & ~MShape ) | HLine ); // force HLine +} + +void KDHorizontalLine::setTitle( const QString & title ) { + if ( mTitle == title ) + return; + mTitle = title; + calculateFrame(); + update(); + updateGeometry(); +#ifdef QT_ACCESSIBILITY_SUPPORT + QAccessible::updateAccessibility( this, 0, QAccessible::NameChanged ); +#endif +} + +void KDHorizontalLine::calculateFrame() { + mLenVisible = mTitle.length(); +#if 0 + if ( mLenVisible ) { + const QFontMetrics fm = fontMetrics(); + while ( mLenVisible ) { + const int tw = fm.width( mTitle, mLenVisible ) + 4*fm.width(QChar(' ')); + if ( tw < width() ) + break; + mLenVisible--; + } + qDebug( "mLenVisible = %d (of %d)", mLenVisible, mTitle.length() ); + if ( mLenVisible ) { // but do we also have a visible label? + QRect r = rect(); + const int va = style().styleHint( QStyle::SH_GroupBox_TextLabelVerticalAlignment, this ); + if( va & AlignVCenter ) + r.setTop( fm.height() / 2 ); // frame rect should be + else if( va & AlignTop ) + r.setTop( fm.ascent() ); + setFrameRect( r ); // smaller than client rect + return; + } + } + // no visible label + setFrameRect( QRect(0,0,0,0) ); // then use client rect +#endif +} + +QSizePolicy KDHorizontalLine::sizePolicy() const { + return QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ); +} + +QSize KDHorizontalLine::sizeHint() const { + return minimumSizeHint(); +} + +QSize KDHorizontalLine::minimumSizeHint() const { + const int w = fontMetrics().width( mTitle, mLenVisible ) + + fontMetrics().width( QChar( ' ' ) ); + const int h = fontMetrics().height(); + return QSize( QMAX( w, indentHint() ), h ).expandedTo( qApp->globalStrut() ); +} + +void KDHorizontalLine::paintEvent( QPaintEvent * e ) { + QPainter paint( this ); + + if ( mLenVisible ) { // draw title + const QFontMetrics & fm = paint.fontMetrics(); + const int h = fm.height(); + const int tw = fm.width( mTitle, mLenVisible ) + fm.width(QChar(' ')); + int x; + if ( mAlign & AlignHCenter ) // center alignment + x = frameRect().width()/2 - tw/2; + else if ( mAlign & AlignRight ) // right alignment + x = frameRect().width() - tw; + else if ( mAlign & AlignLeft ) // left alignment + x = 0; + else { // auto align + if( QApplication::reverseLayout() ) + x = frameRect().width() - tw; + else + x = 0; + } + QRect r( x, 0, tw, h ); + int va = style().styleHint( QStyle::SH_GroupBox_TextLabelVerticalAlignment, this ); + if ( va & AlignTop ) + r.moveBy( 0, fm.descent() ); + const QColor pen( (QRgb) style().styleHint( QStyle::SH_GroupBox_TextLabelColor, this ) ); +#if QT_VERSION >= 0x030300 + if ( !style().styleHint( QStyle::SH_UnderlineAccelerator, this ) ) + va |= NoAccel; +#endif + style().drawItem( &paint, r, ShowPrefix | AlignHCenter | va, colorGroup(), + isEnabled(), 0, mTitle, -1, ownPalette() ? 0 : &pen ); + paint.setClipRegion( e->region().subtract( r ) ); // clip everything but title + } + drawFrame( &paint ); + drawContents( &paint ); +} + +// static +int KDHorizontalLine::indentHint() { + return 30; +} + +#include "kdhorizontalline.moc" diff --git a/certmanager/lib/ui/kdhorizontalline.h b/certmanager/lib/ui/kdhorizontalline.h new file mode 100644 index 000000000..a79682ebd --- /dev/null +++ b/certmanager/lib/ui/kdhorizontalline.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++ -*- + KD Tools - a set of useful widgets for Qt +*/ + +/**************************************************************************** +** Copyright (C) 2005 Klarälvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.klaralvdalens-datakonsult.se/?page=products for +** information about KD Tools Commercial License Agreements. +** +** Contact info@klaralvdalens-datakonsult.se if any conditions of this +** licensing are not clear to you. +** +** 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. +** +**********************************************************************/ + +#ifndef __KDTOOLS__KDHORIZONTALLINE_H__ +#define __KDTOOLS__KDHORIZONTALLINE_H__ + +#include <qframe.h> +#include <qstring.h> + +class KDHorizontalLine : public QFrame { + Q_OBJECT + Q_PROPERTY( QString title READ title WRITE setTitle ) +public: + KDHorizontalLine( QWidget * parent=0, const char * name=0, WFlags f=0 ); + KDHorizontalLine( const QString & title, QWidget * parent=0, const char * name=0, WFlags f=0 ); + ~KDHorizontalLine(); + + QString title() const { return mTitle; } + + /*! \reimp to hard-code the frame shape */ + void setFrameStyle( int style ); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + QSizePolicy sizePolicy() const; + + static int indentHint(); + +public slots: + virtual void setTitle( const QString & title ); + +protected: + void paintEvent( QPaintEvent * ); + +private: + void calculateFrame(); + +private: + QString mTitle; + Qt::AlignmentFlags mAlign; + int mLenVisible; +}; + +#endif /* __KDTOOLS__KDHORIZONTALLINE_H__ */ + diff --git a/certmanager/lib/ui/keyapprovaldialog.cpp b/certmanager/lib/ui/keyapprovaldialog.cpp new file mode 100644 index 000000000..7af85a0bb --- /dev/null +++ b/certmanager/lib/ui/keyapprovaldialog.cpp @@ -0,0 +1,227 @@ +/* -*- c++ -*- + keyapprovaldialog.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Based on kpgpui.h + Copyright (C) 2001,2002 the KPGP authors + See file libkdenetwork/AUTHORS.kpgp for details + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "keyapprovaldialog.h" + +#include "keyrequester.h" + +#include <cryptplugfactory.h> +#include <kleo/cryptobackend.h> + +#include <klocale.h> +#include <kglobalsettings.h> +#include <kseparator.h> + +#include <qstringlist.h> +#include <qframe.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qcombobox.h> +#include <qscrollview.h> +#include <qpushbutton.h> + +#include <gpgmepp/key.h> + +#include <assert.h> + +static Kleo::EncryptionPreference cb2pref( int i ) { + switch ( i ) { + default: + case 0: return Kleo::UnknownPreference; + case 1: return Kleo::NeverEncrypt; + case 2: return Kleo::AlwaysEncrypt; + case 3: return Kleo::AlwaysEncryptIfPossible; + case 4: return Kleo::AlwaysAskForEncryption; + case 5: return Kleo::AskWheneverPossible; + } +} + +static int pref2cb( Kleo::EncryptionPreference p ) { + switch ( p ) { + default: return 0; + case Kleo::NeverEncrypt: return 1; + case Kleo::AlwaysEncrypt: return 2; + case Kleo::AlwaysEncryptIfPossible: return 3; + case Kleo::AlwaysAskForEncryption: return 4; + case Kleo::AskWheneverPossible: return 5; + } +} + +static QStringList preferencesStrings() { + return QStringList() << i18n("<none>") + << i18n("Never Encrypt with This Key") + << i18n("Always Encrypt with This Key") + << i18n("Encrypt Whenever Encryption is Possible") + << i18n("Always Ask") + << i18n("Ask Whenever Encryption is Possible"); +} + + +struct Kleo::KeyApprovalDialog::Private { + Private() : selfRequester( 0 ), prefsChanged( false ) {} + + Kleo::KeyRequester * selfRequester; + QStringList addresses; + std::vector<Kleo::KeyRequester*> requesters; + std::vector<QComboBox*> preferences; + bool prefsChanged; +}; + +Kleo::KeyApprovalDialog::KeyApprovalDialog( const std::vector<Item> & recipients, + const std::vector<GpgME::Key> & sender, + QWidget * parent, const char * name, + bool modal ) + : KDialogBase( parent, name, modal, i18n("Encryption Key Approval"), Ok|Cancel, Ok ), + d( 0 ) +{ + assert( !recipients.empty() ); + + d = new Private(); + + QFrame *page = makeMainWidget(); + QVBoxLayout * vlay = new QVBoxLayout( page, 0, spacingHint() ); + + vlay->addWidget( new QLabel( i18n("The following keys will be used for encryption:"), page ) ); + + QScrollView * sv = new QScrollView( page ); + sv->setResizePolicy( QScrollView::AutoOneFit ); + vlay->addWidget( sv ); + + QWidget * view = new QWidget( sv->viewport() ); + + QGridLayout * glay = new QGridLayout( view, 3, 2, marginHint(), spacingHint() ); + glay->setColStretch( 1, 1 ); + sv->addChild( view ); + + int row = -1; + + if ( !sender.empty() ) { + ++row; + glay->addWidget( new QLabel( i18n("Your keys:"), view ), row, 0 ); + d->selfRequester = new EncryptionKeyRequester( true, EncryptionKeyRequester::AllProtocols, view ); + d->selfRequester->setKeys( sender ); + glay->addWidget( d->selfRequester, row, 1 ); + ++row; + glay->addMultiCellWidget( new KSeparator( Horizontal, view ), row, row, 0, 1 ); + } + + const QStringList prefs = preferencesStrings(); + + for ( std::vector<Item>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it ) { + ++row; + glay->addWidget( new QLabel( i18n("Recipient:"), view ), row, 0 ); + glay->addWidget( new QLabel( it->address, view ), row, 1 ); + d->addresses.push_back( it->address ); + + ++row; + glay->addWidget( new QLabel( i18n("Encryption keys:"), view ), row, 0 ); + KeyRequester * req = new EncryptionKeyRequester( true, EncryptionKeyRequester::AllProtocols, view ); + req->setKeys( it->keys ); + glay->addWidget( req, row, 1 ); + d->requesters.push_back( req ); + + ++row; + glay->addWidget( new QLabel( i18n("Encryption preference:"), view ), row, 0 ); + QComboBox * cb = new QComboBox( false, view ); + cb->insertStringList( prefs ); + glay->addWidget( cb, row, 1 ); + cb->setCurrentItem( pref2cb( it->pref ) ); + connect( cb, SIGNAL(activated(int)), SLOT(slotPrefsChanged()) ); + d->preferences.push_back( cb ); + } + + // calculate the optimal width for the dialog + const int dialogWidth = marginHint() + + sv->frameWidth() + + view->sizeHint().width() + + sv->verticalScrollBar()->sizeHint().width() + + sv->frameWidth() + + marginHint() + + 2; + // calculate the optimal height for the dialog + const int dialogHeight = marginHint() + + fontMetrics().height() + + spacingHint() + + sv->frameWidth() + + view->sizeHint().height() + + sv->horizontalScrollBar()->sizeHint().height() + + sv->frameWidth() + + spacingHint() + + actionButton( KDialogBase::Cancel )->sizeHint().height() + + marginHint() + + 2; + + // don't make the dialog too large + const QRect desk = KGlobalSettings::desktopGeometry( this ); + setInitialSize( QSize( kMin( dialogWidth, 3 * desk.width() / 4 ), + kMin( dialogHeight, 7 * desk.height() / 8 ) ) ); +} + +Kleo::KeyApprovalDialog::~KeyApprovalDialog() { + delete d; d = 0; +} + +std::vector<GpgME::Key> Kleo::KeyApprovalDialog::senderKeys() const { + return d->selfRequester ? d->selfRequester->keys() : std::vector<GpgME::Key>() ; +} + +std::vector<Kleo::KeyApprovalDialog::Item> Kleo::KeyApprovalDialog::items() const { + assert( d->requesters.size() == d->addresses.size() ); + assert( d->requesters.size() == d->preferences.size() ); + + std::vector<Item> result; + result.reserve( d->requesters.size() ); + QStringList::const_iterator ait = d->addresses.begin(); + std::vector<KeyRequester*>::const_iterator rit = d->requesters.begin(); + std::vector<QComboBox*>::const_iterator cit = d->preferences.begin(); + while ( ait != d->addresses.end() ) + result.push_back( Item( *ait++, (*rit++)->keys(), cb2pref( (*cit++)->currentItem() ) ) ); + return result; +} + +bool Kleo::KeyApprovalDialog::preferencesChanged() const { + return d->prefsChanged; +} + +void Kleo::KeyApprovalDialog::slotPrefsChanged() { + d->prefsChanged = true; +} + +#include "keyapprovaldialog.moc" diff --git a/certmanager/lib/ui/keyapprovaldialog.h b/certmanager/lib/ui/keyapprovaldialog.h new file mode 100644 index 000000000..224530a71 --- /dev/null +++ b/certmanager/lib/ui/keyapprovaldialog.h @@ -0,0 +1,92 @@ +/* -*- c++ -*- + keyselectiondialog.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Based on kpgpui.h + Copyright (C) 2001,2002 the KPGP authors + See file libkdenetwork/AUTHORS.kpgp for details + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifndef __KLEO_KEYAPPROVALDIALOG_H__ +#define __KLEO_KEYAPPROVALDIALOG_H__ + +#include <kleo/enum.h> + +#include <kdialogbase.h> +#include <kdepimmacros.h> + +#include <kpgpkey.h> // for EncryptPref +#include <gpgmepp/key.h> + +#include <vector> + +namespace GpgME { + class Key; +} + +class QStringList; + +namespace Kleo { + + class KDE_EXPORT KeyApprovalDialog : public KDialogBase { + Q_OBJECT + public: + struct Item { + Item() : pref( UnknownPreference ) {} + Item( const QString & a, const std::vector<GpgME::Key> & k, + EncryptionPreference p=UnknownPreference ) + : address( a ), keys( k ), pref( p ) {} + QString address; + std::vector<GpgME::Key> keys; + EncryptionPreference pref; + }; + + KeyApprovalDialog( const std::vector<Item> & recipients, + const std::vector<GpgME::Key> & sender, + QWidget * parent=0, const char * name=0, + bool modal=true ); + ~KeyApprovalDialog(); + + std::vector<Item> items() const; + std::vector<GpgME::Key> senderKeys() const; + + bool preferencesChanged() const; + + private slots: + void slotPrefsChanged(); + + private: + class Private; + Private * d; + }; + +} // namespace Kleo + +#endif // __KLEO_KEYAPPROVALDIALOG_H__ diff --git a/certmanager/lib/ui/keylistview.cpp b/certmanager/lib/ui/keylistview.cpp new file mode 100644 index 000000000..98534a4b7 --- /dev/null +++ b/certmanager/lib/ui/keylistview.cpp @@ -0,0 +1,869 @@ +/* + keylistview.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "keylistview.h" + +#include <kdebug.h> + +#include <qfontmetrics.h> +#include <qtooltip.h> +#include <qrect.h> +#include <qheader.h> +#include <qpoint.h> +#include <qptrlist.h> +#include <qpainter.h> +#include <qfont.h> +#include <qcolor.h> +#include <qtimer.h> +#include <qcstring.h> + +#include <gpgmepp/key.h> + +#include <vector> +#include <map> + +#include <assert.h> + +static const int updateDelayMilliSecs = 500; + +namespace { + + class ItemToolTip : public QToolTip { + public: + ItemToolTip( Kleo::KeyListView * parent ); + protected: + void maybeTip( const QPoint & p ); + private: + Kleo::KeyListView * mKeyListView; + }; + + ItemToolTip::ItemToolTip( Kleo::KeyListView * parent ) + : QToolTip( parent->viewport() ), mKeyListView( parent ) {} + + void ItemToolTip::maybeTip( const QPoint & p ) { + if ( !mKeyListView ) + return; + + const QListViewItem * item = mKeyListView->itemAt( p ); + if ( !item ) + return; + + const QRect itemRect = mKeyListView->itemRect( item ); + if ( !itemRect.isValid() ) + return; + + const int col = mKeyListView->header()->sectionAt( p.x() ); + if ( col == -1 ) + return; + + const QRect headerRect = mKeyListView->header()->sectionRect( col ); + if ( !headerRect.isValid() ) + return; + + const QRect cellRect( headerRect.left(), itemRect.top(), + headerRect.width(), itemRect.height() ); + + QString tipStr; + if ( const Kleo::KeyListViewItem * klvi = Kleo::lvi_cast<Kleo::KeyListViewItem>( item ) ) + tipStr = klvi->toolTip( col ); + else + tipStr = item->text( col ) ; + + if ( !tipStr.isEmpty() ) + tip( cellRect, tipStr ); + } + +} // anon namespace + +struct Kleo::KeyListView::Private { + Private() : updateTimer( 0 ), itemToolTip( 0 ) {} + + std::vector<GpgME::Key> keyBuffer; + QTimer * updateTimer; + QToolTip * itemToolTip; + std::map<QCString,KeyListViewItem*> itemMap; +}; + +// a list of signals where we want to replace QListViewItem with +// Kleo:KeyListViewItem: +static const struct { + const char * source; + const char * target; +} signalReplacements[] = { + { SIGNAL(doubleClicked(QListViewItem*,const QPoint&,int)), + SLOT(slotEmitDoubleClicked(QListViewItem*,const QPoint&,int)) }, + { SIGNAL(returnPressed(QListViewItem*)), + SLOT(slotEmitReturnPressed(QListViewItem*)) }, + { SIGNAL(selectionChanged(QListViewItem*)), + SLOT(slotEmitSelectionChanged(QListViewItem*)) }, + { SIGNAL(contextMenu(KListView*, QListViewItem*,const QPoint&)), + SLOT(slotEmitContextMenu(KListView*, QListViewItem*,const QPoint&)) }, +}; +static const int numSignalReplacements = sizeof signalReplacements / sizeof *signalReplacements; + + +Kleo::KeyListView::KeyListView( const ColumnStrategy * columnStrategy, const DisplayStrategy * displayStrategy, QWidget * parent, const char * name, WFlags f ) + : KListView( parent, name ), + mColumnStrategy( columnStrategy ), + mDisplayStrategy ( displayStrategy ), + mHierarchical( false ) +{ + setWFlags( f ); + + d = new Private(); + + d->updateTimer = new QTimer( this ); + connect( d->updateTimer, SIGNAL(timeout()), SLOT(slotUpdateTimeout()) ); + + if ( !columnStrategy ) { + kdWarning(5150) << "Kleo::KeyListView: need a column strategy to work with!" << endl; + return; + } + + const QFontMetrics fm = fontMetrics(); + + for ( int col = 0 ; !columnStrategy->title( col ).isEmpty() ; ++col ) { + addColumn( columnStrategy->title( col ), columnStrategy->width( col, fm ) ); + setColumnWidthMode( col, columnStrategy->widthMode( col ) ); + } + + setAllColumnsShowFocus( true ); + setShowToolTips( false ); // we do it instead... + + for ( int i = 0 ; i < numSignalReplacements ; ++i ) + connect( this, signalReplacements[i].source, signalReplacements[i].target ); + + QToolTip::remove( this ); + QToolTip::remove( viewport() ); // make double sure :) + d->itemToolTip = new ItemToolTip( this ); +} + +Kleo::KeyListView::~KeyListView() { + d->updateTimer->stop(); + // need to clear here, since in ~QListView, our children won't have + // a valid listView() pointing to us anymore, and their dtors try to + // unregister from us. + clear(); + assert( d->itemMap.size() == 0 ); + // need to delete the tooltip ourselves, as ~QToolTip isn't virtual :o + delete d->itemToolTip; d->itemToolTip = 0; + delete d; d = 0; + delete mColumnStrategy; mColumnStrategy = 0; + delete mDisplayStrategy; mDisplayStrategy = 0; +} + +void Kleo::KeyListView::insertItem( QListViewItem * qlvi ) { + //kdDebug() << "Kleo::KeyListView::insertItem( " << qlvi << " )" << endl; + KListView::insertItem( qlvi ); + if ( KeyListViewItem * item = lvi_cast<KeyListViewItem>( qlvi ) ) + registerItem( item ); +} + +void Kleo::KeyListView::takeItem( QListViewItem * qlvi ) { + //kdDebug() << "Kleo::KeyListView::takeItem( " << qlvi << " )" << endl; + if ( KeyListViewItem * item = lvi_cast<KeyListViewItem>( qlvi ) ) + deregisterItem( item ); + KListView::takeItem( qlvi ); +} + + +void Kleo::KeyListView::setHierarchical( bool hier ) { + if ( hier == mHierarchical ) + return; + mHierarchical = hier; + if ( hier ) + gatherScattered(); + else + scatterGathered( firstChild() ); +} + +void Kleo::KeyListView::slotAddKey( const GpgME::Key & key ) { + if ( key.isNull() ) + return; + + d->keyBuffer.push_back( key ); + if ( !d->updateTimer->isActive() ) + d->updateTimer->start( updateDelayMilliSecs, true /* single-shot */ ); +} + +void Kleo::KeyListView::slotUpdateTimeout() { + if ( d->keyBuffer.empty() ) + return; + + const bool wasUpdatesEnabled = viewport()->isUpdatesEnabled(); + if ( wasUpdatesEnabled ) + viewport()->setUpdatesEnabled( false ); + kdDebug( 5150 ) << "Kleo::KeyListView::slotUpdateTimeout(): processing " + << d->keyBuffer.size() << " items en block" << endl; + if ( hierarchical() ) { + for ( std::vector<GpgME::Key>::const_iterator it = d->keyBuffer.begin() ; it != d->keyBuffer.end() ; ++it ) + doHierarchicalInsert( *it ); + gatherScattered(); + } else { + for ( std::vector<GpgME::Key>::const_iterator it = d->keyBuffer.begin() ; it != d->keyBuffer.end() ; ++it ) + (void)new KeyListViewItem( this, *it ); + } + if ( wasUpdatesEnabled ) + viewport()->setUpdatesEnabled( true ); + d->keyBuffer.clear(); +} + +void Kleo::KeyListView::clear() { + d->updateTimer->stop(); + d->keyBuffer.clear(); + KListView::clear(); +} + +void Kleo::KeyListView::registerItem( KeyListViewItem * item ) { + //kdDebug() << "registerItem( " << item << " )" << endl; + if ( !item ) + return; + const QCString fpr = item->key().primaryFingerprint(); + if ( !fpr.isEmpty() ) + d->itemMap.insert( std::make_pair( fpr, item ) ); +} + +void Kleo::KeyListView::deregisterItem( const KeyListViewItem * item ) { + //kdDebug() << "deregisterItem( KeyLVI: " << item << " )" << endl; + if ( !item ) + return; + std::map<QCString,KeyListViewItem*>::iterator it + = d->itemMap.find( item->key().primaryFingerprint() ); + if ( it == d->itemMap.end() ) + return; + Q_ASSERT( it->second == item ); + if ( it->second != item ) + return; + d->itemMap.erase( it ); +} + +void Kleo::KeyListView::doHierarchicalInsert( const GpgME::Key & key ) { + const QCString fpr = key.primaryFingerprint(); + if ( fpr.isEmpty() ) + return; + KeyListViewItem * item = 0; + if ( !key.isRoot() ) + if ( KeyListViewItem * parent = itemByFingerprint( key.chainID() ) ) { + item = new KeyListViewItem( parent, key ); + parent->setOpen( true ); + } + if ( !item ) + item = new KeyListViewItem( this, key ); // top-level (for now) + + d->itemMap.insert( std::make_pair( fpr, item ) ); +} + +void Kleo::KeyListView::gatherScattered() { + KeyListViewItem * item = firstChild(); + while ( item ) { + KeyListViewItem * cur = item; + item = item->nextSibling(); + if ( cur->key().isRoot() ) + continue; + if ( KeyListViewItem * parent = itemByFingerprint( cur->key().chainID() ) ) { + // found a new parent... + // ### todo: optimize by suppressing removing/adding the item to the itemMap... + takeItem( cur ); + parent->insertItem( cur ); + parent->setOpen( true ); + } + } +} + +void Kleo::KeyListView::scatterGathered( QListViewItem * start ) { + QListViewItem * item = start; + while ( item ) { + QListViewItem * cur = item; + item = item->nextSibling(); + + scatterGathered( cur->firstChild() ); + assert( cur->childCount() == 0 ); + + // ### todo: optimize by suppressing removing/adding the item to the itemMap... + if ( cur->parent() ) + cur->parent()->takeItem( cur ); + else + takeItem( cur ); + insertItem( cur ); + } +} + +Kleo::KeyListViewItem * Kleo::KeyListView::itemByFingerprint( const QCString & s ) const { + if ( s.isEmpty() ) + return 0; + const std::map<QCString,KeyListViewItem*>::const_iterator it = d->itemMap.find( s ); + if ( it == d->itemMap.end() ) + return 0; + return it->second; +} + + +void Kleo::KeyListView::slotRefreshKey( const GpgME::Key & key ) { + const char * fpr = key.primaryFingerprint(); + if ( !fpr ) + return; + if ( KeyListViewItem * item = itemByFingerprint( fpr ) ) + item->setKey ( key ); + else + // none found -> add it + slotAddKey( key ); +} + +// slots for the emission of covariant signals: + +void Kleo::KeyListView::slotEmitDoubleClicked( QListViewItem * item, const QPoint & p, int col ) { + if ( !item || lvi_cast<KeyListViewItem>( item ) ) + emit doubleClicked( static_cast<KeyListViewItem*>( item ), p, col ); +} + +void Kleo::KeyListView::slotEmitReturnPressed( QListViewItem * item ) { + if ( !item || lvi_cast<KeyListViewItem>( item ) ) + emit returnPressed( static_cast<KeyListViewItem*>( item ) ); +} + +void Kleo::KeyListView::slotEmitSelectionChanged( QListViewItem * item ) { + if ( !item || lvi_cast<KeyListViewItem>( item ) ) + emit selectionChanged( static_cast<KeyListViewItem*>( item ) ); +} + +void Kleo::KeyListView::slotEmitContextMenu( KListView*, QListViewItem * item, const QPoint & p ) { + if ( !item || lvi_cast<KeyListViewItem>( item ) ) + emit contextMenu( static_cast<KeyListViewItem*>( item ), p ); +} + +// +// +// KeyListViewItem +// +// + +Kleo::KeyListViewItem::KeyListViewItem( KeyListView * parent, const GpgME::Key & key ) + : QListViewItem( parent ) +{ + setKey( key ); +} + +Kleo::KeyListViewItem::KeyListViewItem( KeyListView * parent, KeyListViewItem * after, const GpgME::Key & key ) + : QListViewItem( parent, after ) +{ + setKey( key ); +} + +Kleo::KeyListViewItem::KeyListViewItem( KeyListViewItem * parent, const GpgME::Key & key ) + : QListViewItem( parent ) +{ + setKey( key ); +} + +Kleo::KeyListViewItem::KeyListViewItem( KeyListViewItem * parent, KeyListViewItem * after, const GpgME::Key & key ) + : QListViewItem( parent, after ) +{ + setKey( key ); +} + +Kleo::KeyListViewItem::~KeyListViewItem() { + // delete the children first... When children are deleted in the + // QLVI dtor, they don't have listView() anymore, thus they don't + // call deregister( this ), leading to stale entries in the + // itemMap... + while ( QListViewItem * item = firstChild() ) + delete item; + // better do this here, too, since deletion is top-down and thus + // we're deleted when our parent item is no longer a + // KeyListViewItem, but a mere QListViewItem, so our takeItem() + // overload is gone by that time... + if ( KeyListView * lv = listView() ) + lv->deregisterItem( this ); +} + +void Kleo::KeyListViewItem::setKey( const GpgME::Key & key ) { + KeyListView * lv = listView(); + if ( lv ) + lv->deregisterItem( this ); + mKey = key; + if ( lv ) + lv->registerItem( this ); + + // the ColumnStrategy operations might be very slow, so cache their + // result here, where we're non-const :) + const Kleo::KeyListView::ColumnStrategy * cs = lv ? lv->columnStrategy() : 0 ; + if ( !cs ) + return; + const int numCols = lv ? lv->columns() : 0 ; + for ( int i = 0 ; i < numCols ; ++i ) { + setText( i, cs->text( key, i ) ); + if ( const QPixmap * pix = cs->pixmap( key, i ) ) + setPixmap( i, *pix ); + } + repaint(); +} + +QString Kleo::KeyListViewItem::toolTip( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->toolTip( key(), col ) + : QString::null ; +} + +int Kleo::KeyListViewItem::compare( QListViewItem * item, int col, bool ascending ) const { + if ( !item || item->rtti() != RTTI || !listView() || !listView()->columnStrategy() ) + return QListViewItem::compare( item, col, ascending ); + KeyListViewItem * that = static_cast<KeyListViewItem*>( item ); + return listView()->columnStrategy()->compare( this->key(), that->key(), col ); +} + +void Kleo::KeyListViewItem::paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int alignment ) { + const KeyListView::DisplayStrategy * ds = listView() ? listView()->displayStrategy() : 0 ; + if ( !ds ) { + QListViewItem::paintCell( p, cg, column, width, alignment ); + return; + } + const QColor fg = ds->keyForeground( key(), cg.text() ); + const QColor bg = ds->keyBackground( key(), cg.base() ); + const QFont f = ds->keyFont( key(), p->font() ); + + QColorGroup _cg = cg; + p->setFont( f ); + _cg.setColor( QColorGroup::Text, fg ); + _cg.setColor( QColorGroup::Base, bg ); + + QListViewItem::paintCell( p, _cg, column, width, alignment ); +} + +void Kleo::KeyListViewItem::insertItem( QListViewItem * qlvi ) { + //kdDebug() << "Kleo::KeyListViewItem::insertItem( " << qlvi << " )" << endl; + QListViewItem::insertItem( qlvi ); + if ( KeyListViewItem * item = lvi_cast<KeyListViewItem>( qlvi ) ) + listView()->registerItem( item ); +} + +void Kleo::KeyListViewItem::takeItem( QListViewItem * qlvi ) { + //kdDebug() << "Kleo::KeyListViewItem::takeItem( " << qlvi << " )" << endl; + if ( KeyListViewItem * item = lvi_cast<KeyListViewItem>( qlvi ) ) + listView()->deregisterItem( item ); + QListViewItem::takeItem( qlvi ); +} + + +// +// +// SubkeyKeyListViewItem +// +// + +Kleo::SubkeyKeyListViewItem::SubkeyKeyListViewItem( KeyListView * parent, const GpgME::Subkey & subkey ) + : KeyListViewItem( parent, subkey.parent() ), mSubkey( subkey ) +{ + +} + +Kleo::SubkeyKeyListViewItem::SubkeyKeyListViewItem( KeyListView * parent, KeyListViewItem * after, const GpgME::Subkey & subkey ) + : KeyListViewItem( parent, after, subkey.parent() ), mSubkey( subkey ) +{ + +} + +Kleo::SubkeyKeyListViewItem::SubkeyKeyListViewItem( KeyListViewItem * parent, const GpgME::Subkey & subkey ) + : KeyListViewItem( parent, subkey.parent() ), mSubkey( subkey ) +{ + +} + +Kleo::SubkeyKeyListViewItem::SubkeyKeyListViewItem( KeyListViewItem * parent, KeyListViewItem * after, const GpgME::Subkey & subkey ) + : KeyListViewItem( parent, after, subkey.parent() ), mSubkey( subkey ) +{ + +} + +void Kleo::SubkeyKeyListViewItem::setSubkey( const GpgME::Subkey & subkey ) { + mSubkey = subkey; + setKey( subkey.parent() ); +} + +QString Kleo::SubkeyKeyListViewItem::text( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->subkeyText( subkey(), col ) + : QString::null ; +} + +QString Kleo::SubkeyKeyListViewItem::toolTip( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->subkeyToolTip( subkey(), col ) + : QString::null ; +} + +const QPixmap * Kleo::SubkeyKeyListViewItem::pixmap( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->subkeyPixmap( subkey(), col ) : 0 ; +} + +int Kleo::SubkeyKeyListViewItem::compare( QListViewItem * item, int col, bool ascending ) const { + if ( !item || item->rtti() != RTTI || !listView() || !listView()->columnStrategy() ) + return KeyListViewItem::compare( item, col, ascending ); + SubkeyKeyListViewItem * that = static_cast<SubkeyKeyListViewItem*>( item ); + return listView()->columnStrategy()->subkeyCompare( this->subkey(), that->subkey(), col ); +} + +void Kleo::SubkeyKeyListViewItem::paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int alignment ) { + const KeyListView::DisplayStrategy * ds = listView() ? listView()->displayStrategy() : 0 ; + if ( !ds ) { + QListViewItem::paintCell( p, cg, column, width, alignment ); + return; + } + const QColor fg = ds->subkeyForeground( subkey(), cg.text() ); + const QColor bg = ds->subkeyBackground( subkey(), cg.base() ); + const QFont f = ds->subkeyFont( subkey(), p->font() ); + + QColorGroup _cg = cg; + p->setFont( f ); + _cg.setColor( QColorGroup::Text, fg ); + _cg.setColor( QColorGroup::Base, bg ); + + QListViewItem::paintCell( p, _cg, column, width, alignment ); +} + + +// +// +// UserIDKeyListViewItem +// +// + +Kleo::UserIDKeyListViewItem::UserIDKeyListViewItem( KeyListView * parent, const GpgME::UserID & userID ) + : KeyListViewItem( parent, userID.parent() ), mUserID( userID ) +{ + +} + +Kleo::UserIDKeyListViewItem::UserIDKeyListViewItem( KeyListView * parent, KeyListViewItem * after, const GpgME::UserID & userID ) + : KeyListViewItem( parent, after, userID.parent() ), mUserID( userID ) +{ + +} + +Kleo::UserIDKeyListViewItem::UserIDKeyListViewItem( KeyListViewItem * parent, const GpgME::UserID & userID ) + : KeyListViewItem( parent, userID.parent() ), mUserID( userID ) +{ + +} + +Kleo::UserIDKeyListViewItem::UserIDKeyListViewItem( KeyListViewItem * parent, KeyListViewItem * after, const GpgME::UserID & userID ) + : KeyListViewItem( parent, after, userID.parent() ), mUserID( userID ) +{ + +} + +void Kleo::UserIDKeyListViewItem::setUserID( const GpgME::UserID & userID ) { + mUserID = userID; + setKey( userID.parent() ); +} + +QString Kleo::UserIDKeyListViewItem::text( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->userIDText( userID(), col ) + : QString::null ; +} + +QString Kleo::UserIDKeyListViewItem::toolTip( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->userIDToolTip( userID(), col ) + : QString::null ; +} + +const QPixmap * Kleo::UserIDKeyListViewItem::pixmap( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->userIDPixmap( userID(), col ) : 0 ; +} + +int Kleo::UserIDKeyListViewItem::compare( QListViewItem * item, int col, bool ascending ) const { + if ( !item || item->rtti() != RTTI || !listView() || !listView()->columnStrategy() ) + return KeyListViewItem::compare( item, col, ascending ); + UserIDKeyListViewItem * that = static_cast<UserIDKeyListViewItem*>( item ); + return listView()->columnStrategy()->userIDCompare( this->userID(), that->userID(), col ); +} + + +void Kleo::UserIDKeyListViewItem::paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int alignment ) { + const KeyListView::DisplayStrategy * ds = listView() ? listView()->displayStrategy() : 0 ; + if ( !ds ) { + QListViewItem::paintCell( p, cg, column, width, alignment ); + return; + } + const QColor fg = ds->useridForeground( userID(), cg.text() ); + const QColor bg = ds->useridBackground( userID(), cg.base() ); + const QFont f = ds->useridFont( userID(), p->font() ); + + QColorGroup _cg = cg; + p->setFont( f ); + _cg.setColor( QColorGroup::Text, fg ); + _cg.setColor( QColorGroup::Base, bg ); + + QListViewItem::paintCell( p, _cg, column, width, alignment ); +} + + +// +// +// SignatureKeyListViewItem +// +// + +Kleo::SignatureKeyListViewItem::SignatureKeyListViewItem( KeyListView * parent, const GpgME::UserID::Signature & signature ) + : KeyListViewItem( parent, signature.parent().parent() ), mSignature( signature ) +{ + +} + +Kleo::SignatureKeyListViewItem::SignatureKeyListViewItem( KeyListView * parent, KeyListViewItem * after, const GpgME::UserID::Signature & signature ) + : KeyListViewItem( parent, after, signature.parent().parent() ), mSignature( signature ) +{ + +} + +Kleo::SignatureKeyListViewItem::SignatureKeyListViewItem( KeyListViewItem * parent, const GpgME::UserID::Signature & signature ) + : KeyListViewItem( parent, signature.parent().parent() ), mSignature( signature ) +{ + +} + +Kleo::SignatureKeyListViewItem::SignatureKeyListViewItem( KeyListViewItem * parent, KeyListViewItem * after, const GpgME::UserID::Signature & signature ) + : KeyListViewItem( parent, after, signature.parent().parent() ), mSignature( signature ) +{ + +} + +void Kleo::SignatureKeyListViewItem::setSignature( const GpgME::UserID::Signature & signature ) { + mSignature = signature; + setKey( signature.parent().parent() ); +} + +QString Kleo::SignatureKeyListViewItem::text( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->signatureText( signature(), col ) + : QString::null ; +} + +QString Kleo::SignatureKeyListViewItem::toolTip( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->signatureToolTip( signature(), col ) + : QString::null ; +} + +const QPixmap * Kleo::SignatureKeyListViewItem::pixmap( int col ) const { + return listView() && listView()->columnStrategy() + ? listView()->columnStrategy()->signaturePixmap( signature(), col ) : 0 ; +} + +int Kleo::SignatureKeyListViewItem::compare( QListViewItem * item, int col, bool ascending ) const { + if ( !item || item->rtti() != RTTI || !listView() || !listView()->columnStrategy() ) + return KeyListViewItem::compare( item, col, ascending ); + SignatureKeyListViewItem * that = static_cast<SignatureKeyListViewItem*>( item ); + return listView()->columnStrategy()->signatureCompare( this->signature(), that->signature(), col ); +} + +void Kleo::SignatureKeyListViewItem::paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int alignment ) { + const KeyListView::DisplayStrategy * ds = listView() ? listView()->displayStrategy() : 0 ; + if ( !ds ) { + QListViewItem::paintCell( p, cg, column, width, alignment ); + return; + } + const QColor fg = ds->signatureForeground( signature(), cg.text() ); + const QColor bg = ds->signatureBackground( signature(), cg.base() ); + const QFont f = ds->signatureFont( signature(), p->font() ); + + QColorGroup _cg = cg; + p->setFont( f ); + _cg.setColor( QColorGroup::Text, fg ); + _cg.setColor( QColorGroup::Base, bg ); + + QListViewItem::paintCell( p, _cg, column, width, alignment ); +} + + +// +// +// ColumnStrategy +// +// + +Kleo::KeyListView::ColumnStrategy::~ColumnStrategy() {} + +int Kleo::KeyListView::ColumnStrategy::compare( const GpgME::Key & key1, const GpgME::Key & key2, int col ) const { + return QString::localeAwareCompare( text( key1, col ), text( key2, col ) ); +} + +int Kleo::KeyListView::ColumnStrategy::width( int col, const QFontMetrics & fm ) const { + return fm.width( title( col ) ) * 2; +} + +int Kleo::KeyListView::ColumnStrategy::subkeyCompare( const GpgME::Subkey & sub1, const GpgME::Subkey & sub2, int col ) const { + return QString::localeAwareCompare( subkeyText( sub1, col ), subkeyText( sub2, col ) ); +} + +int Kleo::KeyListView::ColumnStrategy::userIDCompare( const GpgME::UserID & uid1, const GpgME::UserID & uid2, int col ) const { + return QString::localeAwareCompare( userIDText( uid1, col ), userIDText( uid2, col ) ); +} + +int Kleo::KeyListView::ColumnStrategy::signatureCompare( const GpgME::UserID::Signature & sig1, const GpgME::UserID::Signature & sig2, int col ) const { + return QString::localeAwareCompare( signatureText( sig1, col ), signatureText( sig2, col ) ); +} + +QString Kleo::KeyListView::ColumnStrategy::toolTip( const GpgME::Key & key, int col ) const { + return text( key, col ); +} + +QString Kleo::KeyListView::ColumnStrategy::subkeyToolTip( const GpgME::Subkey & sub, int col ) const { + return subkeyText( sub, col ); +} + +QString Kleo::KeyListView::ColumnStrategy::userIDToolTip( const GpgME::UserID & uid, int col ) const { + return userIDText( uid, col ); +} + +QString Kleo::KeyListView::ColumnStrategy::signatureToolTip( const GpgME::UserID::Signature & sig, int col ) const { + return signatureText( sig, col ); +} + +// +// +// DisplayStrategy +// +// + +Kleo::KeyListView::DisplayStrategy::~DisplayStrategy() {} + + +//font +QFont Kleo::KeyListView::DisplayStrategy::keyFont( const GpgME::Key &, const QFont & font ) const { + return font; +} + +QFont Kleo::KeyListView::DisplayStrategy::subkeyFont( const GpgME::Subkey &, const QFont & font ) const { + return font; +} + +QFont Kleo::KeyListView::DisplayStrategy::useridFont( const GpgME::UserID &, const QFont & font ) const { + return font; +} + +QFont Kleo::KeyListView::DisplayStrategy::signatureFont( const GpgME::UserID::Signature &, const QFont & font ) const { + return font; +} + +//foreground +QColor Kleo::KeyListView::DisplayStrategy::keyForeground( const GpgME::Key &, const QColor & fg )const { + return fg; +} + +QColor Kleo::KeyListView::DisplayStrategy::subkeyForeground( const GpgME::Subkey &, const QColor & fg ) const { + return fg; +} + +QColor Kleo::KeyListView::DisplayStrategy::useridForeground( const GpgME::UserID &, const QColor & fg ) const { + return fg; +} + +QColor Kleo::KeyListView::DisplayStrategy::signatureForeground( const GpgME::UserID::Signature &, const QColor & fg ) const { + return fg; +} + +//background +QColor Kleo::KeyListView::DisplayStrategy::keyBackground( const GpgME::Key &, const QColor & bg )const { + return bg; +} + +QColor Kleo::KeyListView::DisplayStrategy::subkeyBackground( const GpgME::Subkey &, const QColor & bg ) const { + return bg; +} + +QColor Kleo::KeyListView::DisplayStrategy::useridBackground( const GpgME::UserID &, const QColor & bg ) const { + return bg; +} + +QColor Kleo::KeyListView::DisplayStrategy::signatureBackground( const GpgME::UserID::Signature &, const QColor & bg ) const { + return bg; +} + + +// +// +// Collection of covariant return reimplementations of QListView(Item) +// members: +// +// + +Kleo::KeyListView * Kleo::KeyListViewItem::listView() const { + return static_cast<Kleo::KeyListView*>( QListViewItem::listView() ); +} + +Kleo::KeyListViewItem * Kleo::KeyListViewItem::nextSibling() const { + return static_cast<Kleo::KeyListViewItem*>( QListViewItem::nextSibling() ); +} + +Kleo::KeyListViewItem * Kleo::KeyListView::firstChild() const { + return static_cast<Kleo::KeyListViewItem*>( KListView::firstChild() ); +} + +Kleo::KeyListViewItem * Kleo::KeyListView::selectedItem() const { + return static_cast<Kleo::KeyListViewItem*>( KListView::selectedItem() ); +} + +static void selectedItems( QPtrList<Kleo::KeyListViewItem> & result, QListViewItem * start ) { + for ( QListViewItem * item = start ; item ; item = item->nextSibling() ) { + if ( item->isSelected() ) + if ( Kleo::KeyListViewItem * i = Kleo::lvi_cast<Kleo::KeyListViewItem>( item ) ) + result.append( i ); + selectedItems( result, item->firstChild() ); + } +} + +QPtrList<Kleo::KeyListViewItem> Kleo::KeyListView::selectedItems() const { + QPtrList<KeyListViewItem> result; + ::selectedItems( result, firstChild() ); + return result; +} + +static bool hasSelection( QListViewItem * start ) { + for ( QListViewItem * item = start ; item ; item = item->nextSibling() ) + if ( item->isSelected() || hasSelection( item->firstChild() ) ) + return true; + return false; +} + +bool Kleo::KeyListView::hasSelection() const { + return ::hasSelection( firstChild() ); +} + +#include "keylistview.moc" diff --git a/certmanager/lib/ui/keylistview.h b/certmanager/lib/ui/keylistview.h new file mode 100644 index 000000000..3ef708771 --- /dev/null +++ b/certmanager/lib/ui/keylistview.h @@ -0,0 +1,323 @@ +/* + keylistview.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifndef __KLEO_KEYLISTVIEW_H__ +#define __KLEO_KEYLISTVIEW_H__ + +#include <klistview.h> + +#include <gpgmepp/key.h> +#include <kdepimmacros.h> + +class QPainter; +class QColorGroup; +class QFont; +class QColor; + +namespace Kleo { + + // work around moc parser bug... +#define TEMPLATE_TYPENAME(T) template <typename T> + TEMPLATE_TYPENAME(T) + inline T * lvi_cast( QListViewItem * item ) { + return item && (item->rtti() & T::RTTI_MASK) == T::RTTI + ? static_cast<T*>( item ) : 0 ; + } + + TEMPLATE_TYPENAME(T) + inline const T * lvi_cast( const QListViewItem * item ) { + return item && (item->rtti() & T::RTTI_MASK) == T::RTTI + ? static_cast<const T*>( item ) : 0 ; + } +#undef TEMPLATE_TYPENAME + + class KeyListView; + + class KDE_EXPORT KeyListViewItem : public QListViewItem { + public: + KeyListViewItem( KeyListView * parent, const GpgME::Key & key ); + KeyListViewItem( KeyListView * parent, KeyListViewItem * after, const GpgME::Key & key ); + KeyListViewItem( KeyListViewItem * parent, const GpgME::Key & key ); + KeyListViewItem( KeyListViewItem * parent, KeyListViewItem * after, const GpgME::Key & key ); + ~KeyListViewItem(); + + void setKey( const GpgME::Key & key ); + const GpgME::Key & key() const { return mKey; } + + enum { RTTI_MASK = 0xFFFFFFF0, RTTI = 0x2C1362E0 }; + + // + // only boring stuff below: + // + virtual QString toolTip( int column ) const; + + /*! \reimp for covariant return */ + KeyListView * listView() const; + /*! \reimp for covariant return */ + KeyListViewItem * nextSibling() const; + /*! \reimp */ + int compare( QListViewItem * other, int col, bool ascending ) const; + /*! \reimp to allow for key() overload above */ + QString key( int col, bool ascending ) const { return QListViewItem::key( col, ascending ); } + /*! \reimp */ + int rtti() const { return RTTI; } + /*! \reimp */ + void paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int alignment ); + /*! \reimp */ + void insertItem( QListViewItem * item ); + /*! \reimp */ + void takeItem( QListViewItem * item ); + + private: + GpgME::Key mKey; + }; + + class KDE_EXPORT SubkeyKeyListViewItem : public KeyListViewItem { + public: + SubkeyKeyListViewItem( KeyListView * parent, const GpgME::Subkey & subkey ); + SubkeyKeyListViewItem( KeyListView * parent, KeyListViewItem * after, const GpgME::Subkey & subkey ); + SubkeyKeyListViewItem( KeyListViewItem * parent, const GpgME::Subkey & subkey ); + SubkeyKeyListViewItem( KeyListViewItem * parent, KeyListViewItem * after, const GpgME::Subkey & subkey ); + + void setSubkey( const GpgME::Subkey & subkey ); + const GpgME::Subkey & subkey() const { return mSubkey; } + + enum { RTTI = KeyListViewItem::RTTI + 1 }; + + // + // only boring stuff below: + // + /*! \reimp */ + QString toolTip( int col ) const; + /*! \reimp */ + QString text( int col ) const; + /*! \reimp */ + const QPixmap * pixmap( int col ) const; + /*! \reimp */ + int compare( QListViewItem * other, int col, bool ascending ) const; + /*! \reimp */ + int rtti() const { return RTTI; } + /*! \reimp */ + void paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int alignment ); + + private: + GpgME::Subkey mSubkey; + }; + + class KDE_EXPORT UserIDKeyListViewItem : public KeyListViewItem { + public: + UserIDKeyListViewItem( KeyListView * parent, const GpgME::UserID & userid ); + UserIDKeyListViewItem( KeyListView * parent, KeyListViewItem * after, const GpgME::UserID & userid ); + UserIDKeyListViewItem( KeyListViewItem * parent, const GpgME::UserID & userid ); + UserIDKeyListViewItem( KeyListViewItem * parent, KeyListViewItem * after, const GpgME::UserID & userid ); + + void setUserID( const GpgME::UserID & userid ); + const GpgME::UserID userID() const { return mUserID; } + + enum { RTTI = KeyListViewItem::RTTI + 2 }; + + // + // only boring stuff below: + // + /*! \reimp */ + QString toolTip( int col ) const; + /*! \reimp */ + QString text( int col ) const; + /*! \reimp */ + const QPixmap * pixmap( int col ) const; + /*! \reimp */ + int compare( QListViewItem * other, int col, bool ascending ) const; + /*! \reimp */ + int rtti() const { return RTTI; } + /*! \reimp */ + void paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int alignment ); + + private: + GpgME::UserID mUserID; + }; + + class KDE_EXPORT SignatureKeyListViewItem : public KeyListViewItem { + public: + SignatureKeyListViewItem( KeyListView * parent, const GpgME::UserID::Signature & sig ); + SignatureKeyListViewItem( KeyListView * parent, KeyListViewItem * after, const GpgME::UserID::Signature & sig ); + SignatureKeyListViewItem( KeyListViewItem * parent, const GpgME::UserID::Signature & sig ); + SignatureKeyListViewItem( KeyListViewItem * parent, KeyListViewItem * after, const GpgME::UserID::Signature & sig ); + + void setSignature( const GpgME::UserID::Signature & sig ); + const GpgME::UserID::Signature & signature() const { return mSignature; } + + enum { RTTI = KeyListViewItem::RTTI + 3 }; + + // + // only boring stuff below: + // + /*! \reimp */ + QString toolTip( int col ) const; + /*! \reimp */ + QString text( int col ) const; + /*! \reimp */ + const QPixmap * pixmap( int col ) const; + /*! \reimp */ + int compare( QListViewItem * other, int col, bool ascending ) const; + /*! \reimp */ + int rtti() const { return RTTI; } + /*! \reimp */ + void paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int alignment ); + + private: + GpgME::UserID::Signature mSignature; + }; + + + class KDE_EXPORT KeyListView : public KListView { + Q_OBJECT + friend class KeyListViewItem; + public: + + class KDE_EXPORT ColumnStrategy { + public: + virtual ~ColumnStrategy(); + virtual QString title( int column ) const = 0; + virtual int width( int column, const QFontMetrics & fm ) const; + virtual QListView::WidthMode widthMode( int ) const { return QListView::Manual; } + + virtual QString text( const GpgME::Key & key, int column ) const = 0; + virtual QString toolTip( const GpgME::Key & key, int column ) const; + virtual const QPixmap * pixmap( const GpgME::Key &, int ) const { return 0; } + virtual int compare( const GpgME::Key & key1, const GpgME::Key & key2, const int column ) const; + + virtual QString subkeyText( const GpgME::Subkey &, int ) const { return QString::null; } + virtual QString subkeyToolTip( const GpgME::Subkey & subkey, int column ) const; + virtual const QPixmap * subkeyPixmap( const GpgME::Subkey &, int ) const { return 0; } + virtual int subkeyCompare( const GpgME::Subkey & subkey1, const GpgME::Subkey & subkey2, const int column ) const; + + virtual QString userIDText( const GpgME::UserID &, int ) const { return QString::null; } + virtual QString userIDToolTip( const GpgME::UserID & userID, int column ) const; + virtual const QPixmap * userIDPixmap( const GpgME::UserID &, int ) const { return 0; } + virtual int userIDCompare( const GpgME::UserID & userID1, const GpgME::UserID & userID2, const int column ) const; + + virtual QString signatureText( const GpgME::UserID::Signature &, int ) const { return QString::null; } + virtual QString signatureToolTip( const GpgME::UserID::Signature & sig, int column ) const; + virtual const QPixmap * signaturePixmap( const GpgME::UserID::Signature &, int ) const { return 0; } + virtual int signatureCompare( const GpgME::UserID::Signature & sig1, const GpgME::UserID::Signature & sig2, const int column ) const; + }; + + class KDE_EXPORT DisplayStrategy { + public: + virtual ~DisplayStrategy(); + //font + virtual QFont keyFont( const GpgME::Key &, const QFont & ) const; + virtual QFont subkeyFont( const GpgME::Subkey &, const QFont & ) const; + virtual QFont useridFont( const GpgME::UserID &, const QFont & ) const; + virtual QFont signatureFont( const GpgME::UserID::Signature & , const QFont & ) const; + //foreground + virtual QColor keyForeground( const GpgME::Key & , const QColor & ) const; + virtual QColor subkeyForeground( const GpgME::Subkey &, const QColor & ) const; + virtual QColor useridForeground( const GpgME::UserID &, const QColor & ) const; + virtual QColor signatureForeground( const GpgME::UserID::Signature &, const QColor & ) const; + //background + virtual QColor keyBackground( const GpgME::Key &, const QColor & ) const; + virtual QColor subkeyBackground( const GpgME::Subkey &, const QColor & ) const; + virtual QColor useridBackground( const GpgME::UserID &, const QColor & ) const; + virtual QColor signatureBackground( const GpgME::UserID::Signature &, const QColor & ) const; + }; + + KeyListView( const ColumnStrategy * strategy, + const DisplayStrategy * display=0, + QWidget * parent=0, const char * name=0, WFlags f=0 ); + + ~KeyListView(); + + const ColumnStrategy * columnStrategy() const { return mColumnStrategy; } + const DisplayStrategy * displayStrategy() const { return mDisplayStrategy; } + + bool hierarchical() const { return mHierarchical; } + virtual void setHierarchical( bool hier ); + + void flushKeys() { slotUpdateTimeout(); } + + bool hasSelection() const; + + KeyListViewItem * itemByFingerprint( const QCString & ) const; + + signals: + void doubleClicked( Kleo::KeyListViewItem*, const QPoint&, int ); + void returnPressed( Kleo::KeyListViewItem* ); + void selectionChanged( Kleo::KeyListViewItem* ); + void contextMenu( Kleo::KeyListViewItem*, const QPoint& ); + + public slots: + virtual void slotAddKey( const GpgME::Key & key ); + virtual void slotRefreshKey( const GpgME::Key & key ); + + // + // Only boring stuff below: + // + private slots: + void slotEmitDoubleClicked( QListViewItem*, const QPoint&, int ); + void slotEmitReturnPressed( QListViewItem* ); + void slotEmitSelectionChanged( QListViewItem* ); + void slotEmitContextMenu( KListView*, QListViewItem*, const QPoint& ); + void slotUpdateTimeout(); + + public: + /*! \reimp for covariant return */ + KeyListViewItem * selectedItem() const; + /*! \reimp */ + QPtrList<KeyListViewItem> selectedItems() const; + /*! \reimp for covariant return */ + KeyListViewItem * firstChild() const; + /*! \reimp */ + void clear(); + /*! \reimp */ + void insertItem( QListViewItem * ); + /*! \reimp */ + void takeItem( QListViewItem * ); + + private: + void doHierarchicalInsert( const GpgME::Key & ); + void gatherScattered(); + void scatterGathered( QListViewItem * ); + void registerItem( KeyListViewItem * ); + void deregisterItem( const KeyListViewItem * ); + + private: + const ColumnStrategy * mColumnStrategy; + const DisplayStrategy * mDisplayStrategy; + bool mHierarchical; + + class Private; + Private * d; + }; +} + +#endif // __KLEO_KEYLISTVIEW_H__ diff --git a/certmanager/lib/ui/keyrequester.cpp b/certmanager/lib/ui/keyrequester.cpp new file mode 100644 index 000000000..d537affc5 --- /dev/null +++ b/certmanager/lib/ui/keyrequester.cpp @@ -0,0 +1,481 @@ +/* -*- c++ -*- + keyrequester.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klar�vdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. + + + Based on kpgpui.cpp + Copyright (C) 2001,2002 the KPGP authors + See file libkdenetwork/AUTHORS.kpgp for details + + This file is part of KPGP, the KDE PGP/GnuPG support library. + + KPGP 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. + + 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 + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "keyrequester.h" + +#include "keyselectiondialog.h" + +#include <kleo/keylistjob.h> +#include <kleo/dn.h> +#include <kleo/cryptobackendfactory.h> + +// gpgme++ +#include <gpgmepp/key.h> +#include <gpgmepp/keylistresult.h> + +// KDE +#include <klocale.h> +#include <kiconloader.h> +#include <kdialog.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kpushbutton.h> + +// Qt +#include <qapplication.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qlabel.h> +#include <qregexp.h> + +#include <assert.h> + +Kleo::KeyRequester::KeyRequester( unsigned int allowedKeys, bool multipleKeys, + QWidget * parent, const char * name ) + : QWidget( parent, name ), + mOpenPGPBackend( 0 ), + mSMIMEBackend( 0 ), + mMulti( multipleKeys ), + mKeyUsage( allowedKeys ), + mJobs( 0 ), + d( 0 ) +{ + init(); +} + +Kleo::KeyRequester::KeyRequester( QWidget * parent, const char * name ) + : QWidget( parent, name ), + mOpenPGPBackend( 0 ), + mSMIMEBackend( 0 ), + mMulti( false ), + mKeyUsage( 0 ), + mJobs( 0 ), + d( 0 ) +{ + init(); +} + +void Kleo::KeyRequester::init() +{ + QHBoxLayout * hlay = new QHBoxLayout( this, 0, KDialog::spacingHint() ); + + // the label where the key id is to be displayed: + mLabel = new QLabel( this ); + mLabel->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + + // the button to unset any key: + mEraseButton = new KPushButton( this ); + mEraseButton->setAutoDefault( false ); + mEraseButton->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, + QSizePolicy::Minimum ) ); + mEraseButton->setIconSet( SmallIconSet( QApplication::reverseLayout() ? "locationbar_erase" : "clear_left" ) ); + QToolTip::add( mEraseButton, i18n("Clear") ); + + // the button to call the KeySelectionDialog: + mDialogButton = new QPushButton( i18n("Change..."), this ); + mDialogButton->setAutoDefault( false ); + + hlay->addWidget( mLabel, 1 ); + hlay->addWidget( mEraseButton ); + hlay->addWidget( mDialogButton ); + + connect( mEraseButton, SIGNAL(clicked()), SLOT(slotEraseButtonClicked()) ); + connect( mDialogButton, SIGNAL(clicked()), SLOT(slotDialogButtonClicked()) ); + + setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, + QSizePolicy::Fixed ) ); + + setAllowedKeys( mKeyUsage ); +} + +Kleo::KeyRequester::~KeyRequester() { + +} + +const std::vector<GpgME::Key> & Kleo::KeyRequester::keys() const { + return mKeys; +} + +const GpgME::Key & Kleo::KeyRequester::key() const { + if ( mKeys.empty() ) + return GpgME::Key::null; + else + return mKeys.front(); +} + +void Kleo::KeyRequester::setKeys( const std::vector<GpgME::Key> & keys ) { + mKeys.clear(); + for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) + if ( !it->isNull() ) + mKeys.push_back( *it ); + updateKeys(); +} + +void Kleo::KeyRequester::setKey( const GpgME::Key & key ) { + mKeys.clear(); + if ( !key.isNull() ) + mKeys.push_back( key ); + updateKeys(); +} + +QString Kleo::KeyRequester::fingerprint() const { + if ( mKeys.empty() ) + return QString::null; + else + return mKeys.front().primaryFingerprint(); +} + +QStringList Kleo::KeyRequester::fingerprints() const { + QStringList result; + for ( std::vector<GpgME::Key>::const_iterator it = mKeys.begin() ; it != mKeys.end() ; ++it ) + if ( !it->isNull() ) + if ( const char * fpr = it->primaryFingerprint() ) + result.push_back( fpr ); + return result; +} + +void Kleo::KeyRequester::setFingerprint( const QString & fingerprint ) { + startKeyListJob( fingerprint ); +} + +void Kleo::KeyRequester::setFingerprints( const QStringList & fingerprints ) { + startKeyListJob( fingerprints ); +} + +void Kleo::KeyRequester::updateKeys() { + if ( mKeys.empty() ) { + mLabel->clear(); + return; + } + if ( mKeys.size() > 1 ) + setMultipleKeysEnabled( true ); + + QStringList labelTexts; + QString toolTipText; + for ( std::vector<GpgME::Key>::const_iterator it = mKeys.begin() ; it != mKeys.end() ; ++it ) { + if ( it->isNull() ) + continue; + const QString fpr = it->primaryFingerprint(); + labelTexts.push_back( fpr.right(8) ); + toolTipText += fpr.right(8) + ": "; + if ( const char * uid = it->userID(0).id() ) + if ( it->protocol() == GpgME::Context::OpenPGP ) + toolTipText += QString::fromUtf8( uid ); + else + toolTipText += Kleo::DN( uid ).prettyDN(); + else + toolTipText += i18n("<unknown>"); + toolTipText += '\n'; + } + + mLabel->setText( labelTexts.join(", ") ); + QToolTip::remove( mLabel ); + QToolTip::add( mLabel, toolTipText ); +} + +#ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ +#define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ +static void showKeyListError( QWidget * parent, const GpgME::Error & err ) { + assert( err ); + const QString msg = i18n( "<qt><p>An error occurred while fetching " + "the keys from the backend:</p>" + "<p><b>%1</b></p></qt>" ) + .arg( QString::fromLocal8Bit( err.asString() ) ); + + KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) ); +} +#endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ + +void Kleo::KeyRequester::startKeyListJob( const QStringList & fingerprints ) { + if ( !mSMIMEBackend && !mOpenPGPBackend ) + return; + + mTmpKeys.clear(); + mJobs = 0; + + unsigned int count = 0; + for ( QStringList::const_iterator it = fingerprints.begin() ; it != fingerprints.end() ; ++it ) + if ( !(*it).stripWhiteSpace().isEmpty() ) + ++count; + + if ( !count ) { + // don't fall into the trap that an empty pattern means + // "return all keys" :) + setKey( GpgME::Key::null ); + return; + } + + if ( mOpenPGPBackend ) { + KeyListJob * job = mOpenPGPBackend->keyListJob( false ); // local, no sigs + if ( !job ) { + KMessageBox::error( this, + i18n("The OpenPGP backend does not support listing keys. " + "Check your installation."), + i18n("Key Listing Failed") ); + } else { + connect( job, SIGNAL(result(const GpgME::KeyListResult&)), + SLOT(slotKeyListResult(const GpgME::KeyListResult&)) ); + connect( job, SIGNAL(nextKey(const GpgME::Key&)), + SLOT(slotNextKey(const GpgME::Key&)) ); + + const GpgME::Error err = job->start( fingerprints, + mKeyUsage & Kleo::KeySelectionDialog::SecretKeys && + !( mKeyUsage & Kleo::KeySelectionDialog::PublicKeys ) ); + + if ( err ) + showKeyListError( this, err ); + else + ++mJobs; + } + } + + if ( mSMIMEBackend ) { + KeyListJob * job = mSMIMEBackend->keyListJob( false ); // local, no sigs + if ( !job ) { + KMessageBox::error( this, + i18n("The S/MIME backend does not support listing keys. " + "Check your installation."), + i18n("Key Listing Failed") ); + } else { + connect( job, SIGNAL(result(const GpgME::KeyListResult&)), + SLOT(slotKeyListResult(const GpgME::KeyListResult&)) ); + connect( job, SIGNAL(nextKey(const GpgME::Key&)), + SLOT(slotNextKey(const GpgME::Key&)) ); + + const GpgME::Error err = job->start( fingerprints, + mKeyUsage & Kleo::KeySelectionDialog::SecretKeys && + !( mKeyUsage & Kleo::KeySelectionDialog::PublicKeys ) ); + + if ( err ) + showKeyListError( this, err ); + else + ++mJobs; + } + } + + if ( mJobs > 0 ) { + mEraseButton->setEnabled( false ); + mDialogButton->setEnabled( false ); + } +} + +void Kleo::KeyRequester::slotNextKey( const GpgME::Key & key ) { + if ( !key.isNull() ) + mTmpKeys.push_back( key ); +} + +void Kleo::KeyRequester::slotKeyListResult( const GpgME::KeyListResult & res ) { + if ( res.error() ) + showKeyListError( this, res.error() ); + + if ( --mJobs <= 0 ) { + mEraseButton->setEnabled( true ); + mDialogButton->setEnabled( true ); + + setKeys( mTmpKeys ); + mTmpKeys.clear(); + } +} + + +void Kleo::KeyRequester::slotDialogButtonClicked() { + KeySelectionDialog * dlg = mKeys.empty() + ? new KeySelectionDialog( mDialogCaption, mDialogMessage, mInitialQuery, mKeyUsage, mMulti, false, this ) + : new KeySelectionDialog( mDialogCaption, mDialogCaption, mKeys, mKeyUsage, mMulti, false, this ) ; + + if ( dlg->exec() == QDialog::Accepted ) { + if ( mMulti ) + setKeys( dlg->selectedKeys() ); + else + setKey( dlg->selectedKey() ); + emit changed(); + } + + delete dlg; +} + +void Kleo::KeyRequester::slotEraseButtonClicked() { + if ( !mKeys.empty() ) + emit changed(); + mKeys.clear(); + updateKeys(); +} + +void Kleo::KeyRequester::setDialogCaption( const QString & caption ) { + mDialogCaption = caption; +} + +void Kleo::KeyRequester::setDialogMessage( const QString & msg ) { + mDialogMessage = msg; +} + +bool Kleo::KeyRequester::isMultipleKeysEnabled() const { + return mMulti; +} + +void Kleo::KeyRequester::setMultipleKeysEnabled( bool multi ) { + if ( multi == mMulti ) return; + + if ( !multi && !mKeys.empty() ) + mKeys.erase( mKeys.begin() + 1, mKeys.end() ); + + mMulti = multi; + updateKeys(); +} + +unsigned int Kleo::KeyRequester::allowedKeys() const { + return mKeyUsage; +} + +void Kleo::KeyRequester::setAllowedKeys( unsigned int keyUsage ) { + mKeyUsage = keyUsage; + mOpenPGPBackend = 0; + mSMIMEBackend = 0; + + if ( mKeyUsage & KeySelectionDialog::OpenPGPKeys ) + mOpenPGPBackend = Kleo::CryptoBackendFactory::instance()->openpgp(); + if ( mKeyUsage & KeySelectionDialog::SMIMEKeys ) + mSMIMEBackend = Kleo::CryptoBackendFactory::instance()->smime(); + + if ( mOpenPGPBackend && !mSMIMEBackend ) { + mDialogCaption = i18n("OpenPGP Key Selection"); + mDialogMessage = i18n("Please select an OpenPGP key to use."); + } else if ( !mOpenPGPBackend && mSMIMEBackend ) { + mDialogCaption = i18n("S/MIME Key Selection"); + mDialogMessage = i18n("Please select an S/MIME key to use."); + } else { + mDialogCaption = i18n("Key Selection"); + mDialogMessage = i18n("Please select an (OpenPGP or S/MIME) key to use."); + } +} + +QPushButton * Kleo::KeyRequester::dialogButton() { + return mDialogButton; +} + +QPushButton * Kleo::KeyRequester::eraseButton() { + return mEraseButton; +} + +static inline unsigned int foo( bool openpgp, bool smime, bool trusted, bool valid ) { + unsigned int result = 0; + if ( openpgp ) + result |= Kleo::KeySelectionDialog::OpenPGPKeys; + if ( smime ) + result |= Kleo::KeySelectionDialog::SMIMEKeys; + if ( trusted ) + result |= Kleo::KeySelectionDialog::TrustedKeys; + if ( valid ) + result |= Kleo::KeySelectionDialog::ValidKeys; + return result; +} + +static inline unsigned int encryptionKeyUsage( bool openpgp, bool smime, bool trusted, bool valid ) { + return foo( openpgp, smime, trusted, valid ) | Kleo::KeySelectionDialog::EncryptionKeys | Kleo::KeySelectionDialog::PublicKeys; +} + +static inline unsigned int signingKeyUsage( bool openpgp, bool smime, bool trusted, bool valid ) { + return foo( openpgp, smime, trusted, valid ) | Kleo::KeySelectionDialog::SigningKeys | Kleo::KeySelectionDialog::SecretKeys; +} + +Kleo::EncryptionKeyRequester::EncryptionKeyRequester( bool multi, unsigned int proto, + QWidget * parent, const char * name, + bool onlyTrusted, bool onlyValid ) + : KeyRequester( encryptionKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ), multi, + parent, name ) +{ +} + +Kleo::EncryptionKeyRequester::EncryptionKeyRequester( QWidget * parent, const char * name ) + : KeyRequester( 0, false, parent, name ) +{ +} + +Kleo::EncryptionKeyRequester::~EncryptionKeyRequester() {} + + +void Kleo::EncryptionKeyRequester::setAllowedKeys( unsigned int proto, bool onlyTrusted, bool onlyValid ) +{ + KeyRequester::setAllowedKeys( encryptionKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ) ); +} + +Kleo::SigningKeyRequester::SigningKeyRequester( bool multi, unsigned int proto, + QWidget * parent, const char * name, + bool onlyTrusted, bool onlyValid ) + : KeyRequester( signingKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ), multi, + parent, name ) +{ +} + +Kleo::SigningKeyRequester::SigningKeyRequester( QWidget * parent, const char * name ) + : KeyRequester( 0, false, parent, name ) +{ +} + +Kleo::SigningKeyRequester::~SigningKeyRequester() {} + +void Kleo::SigningKeyRequester::setAllowedKeys( unsigned int proto, bool onlyTrusted, bool onlyValid ) +{ + KeyRequester::setAllowedKeys( signingKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ) ); +} + +void Kleo::KeyRequester::virtual_hook( int, void* ) {} +void Kleo::EncryptionKeyRequester::virtual_hook( int id, void * data ) { + KeyRequester::virtual_hook( id, data ); +} +void Kleo::SigningKeyRequester::virtual_hook( int id, void * data ) { + KeyRequester::virtual_hook( id, data ); +} + +#include "keyrequester.moc" diff --git a/certmanager/lib/ui/keyrequester.h b/certmanager/lib/ui/keyrequester.h new file mode 100644 index 000000000..3de9c508b --- /dev/null +++ b/certmanager/lib/ui/keyrequester.h @@ -0,0 +1,227 @@ +/* -*- c++ -*- + keyrequester.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. + + + Based on kpgpui.h + Copyright (C) 2001,2002 the KPGP authors + See file libkdenetwork/AUTHORS.kpgp for details + + This file is part of KPGP, the KDE PGP/GnuPG support library. + + KPGP 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. + + 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 + */ + +#ifndef __KLEO_UI_KEYREQUESTER_H__ +#define __KLEO_UI_KEYREQUESTER_H__ + +#include <qwidget.h> +#include <kleo/cryptobackend.h> + +#include <vector> +#include <kdepimmacros.h> + +namespace Kleo { + class KeyListView; + class KeyListViewItem; +} + +namespace GpgME { + class Key; + class KeyListResult; +} + +class QStringList; +class QString; +class QPushButton; +class QLabel; + +namespace Kleo { + + /// Base class for SigningKeyRequester and EncryptionKeyRequester + class KDE_EXPORT KeyRequester : public QWidget { + Q_OBJECT + public: + KeyRequester( unsigned int allowedKeys, bool multipleKeys=false, + QWidget * parent=0, const char * name=0 ); + // Constructor for Qt Designer + KeyRequester( QWidget * parent=0, const char * name=0 ); + ~KeyRequester(); + + const GpgME::Key & key() const; + /** Preferred method to set a key for + non-multi-KeyRequesters. Doesn't start a backend + KeyListJob. + */ + void setKey( const GpgME::Key & key ); + + const std::vector<GpgME::Key> & keys() const; + /** Preferred method to set a key for multi-KeyRequesters. Doesn't + start a backend KeyListJob. + */ + void setKeys( const std::vector<GpgME::Key> & keys ); + + QString fingerprint() const; + /** Set the key by fingerprint. Starts a background KeyListJob to + retrive the complete GpgME::Key object + */ + void setFingerprint( const QString & fingerprint ); + + QStringList fingerprints() const; + /** Set the keys by fingerprint. Starts a background KeyListJob to + retrive the complete GpgME::Key objects + */ + void setFingerprints( const QStringList & fingerprints ); + + + QPushButton * eraseButton(); + QPushButton * dialogButton(); + + void setDialogCaption( const QString & caption ); + void setDialogMessage( const QString & message ); + + bool isMultipleKeysEnabled() const; + void setMultipleKeysEnabled( bool enable ); + + unsigned int allowedKeys() const; + void setAllowedKeys( unsigned int allowed ); + + void setInitialQuery( const QString & s ) { mInitialQuery = s; } + const QString & initialQuery() const { return mInitialQuery; } + + signals: + void changed(); + + private: + void init(); + void startKeyListJob( const QStringList & fingerprints ); + void updateKeys(); + + private slots: + void slotNextKey( const GpgME::Key & key ); + void slotKeyListResult( const GpgME::KeyListResult & result ); + void slotDialogButtonClicked(); + void slotEraseButtonClicked(); + + private: + const CryptoBackend::Protocol * mOpenPGPBackend; + const CryptoBackend::Protocol * mSMIMEBackend; + QLabel * mLabel; + QPushButton * mEraseButton; + QPushButton * mDialogButton; + QString mDialogCaption, mDialogMessage, mInitialQuery; + bool mMulti; + unsigned int mKeyUsage; + int mJobs; + std::vector<GpgME::Key> mKeys; + std::vector<GpgME::Key> mTmpKeys; + + private: + class Private; + Private * d; + protected: + virtual void virtual_hook( int, void* ); + }; + + + class KDE_EXPORT EncryptionKeyRequester : public KeyRequester { + Q_OBJECT + public: + enum { OpenPGP = 1, SMIME = 2, AllProtocols = OpenPGP|SMIME }; + + /** + * Preferred constructor + */ + EncryptionKeyRequester( bool multipleKeys=false, unsigned int proto=AllProtocols, + QWidget * parent=0, const char * name=0, + bool onlyTrusted=true, bool onlyValid=true ); + /** + * Constructor for Qt designer + */ + EncryptionKeyRequester( QWidget * parent=0, const char * name=0 ); + ~EncryptionKeyRequester(); + + void setAllowedKeys( unsigned int proto, bool onlyTrusted=true, bool onlyValid=true ); + + private: + class Private; + Private * d; + protected: + virtual void virtual_hook( int, void* ); + }; + + + class KDE_EXPORT SigningKeyRequester : public KeyRequester { + Q_OBJECT + public: + enum { OpenPGP = 1, SMIME = 2, AllProtocols = OpenPGP|SMIME }; + + /** + * Preferred constructor + * @param multipleKeys whether multiple keys can be selected + * + * @param proto the allowed protocols, OpenPGP and/or SMIME + * @param onlyTrusted only show trusted keys + * @param onlyValid only show valid keys + */ + SigningKeyRequester( bool multipleKeys=false, unsigned int proto=AllProtocols, + QWidget * parent=0, const char * name=0, + bool onlyTrusted=true, bool onlyValid=true ); + /** + * Constructor for Qt designer + */ + SigningKeyRequester( QWidget * parent=0, const char * name=0 ); + ~SigningKeyRequester(); + + /* + * Those parameters affect the parameters given to the key selection dialog. + * @param proto the allowed protocols, OpenPGP and/or SMIME + * @param onlyTrusted only show trusted keys + * @param onlyValid only show valid keys + */ + void setAllowedKeys( unsigned int proto, bool onlyTrusted=true, bool onlyValid=true ); + + private: + class Private; + Private * d; + protected: + virtual void virtual_hook( int, void* ); + }; + +} + +#endif // __KLEO_UI_KEYREQUESTER_H__ diff --git a/certmanager/lib/ui/keyselectiondialog.cpp b/certmanager/lib/ui/keyselectiondialog.cpp new file mode 100644 index 000000000..e21cb39d4 --- /dev/null +++ b/certmanager/lib/ui/keyselectiondialog.cpp @@ -0,0 +1,806 @@ +/* -*- c++ -*- + keyselectiondialog.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarävdalens Datakonsult AB + + Based on kpgpui.cpp + Copyright (C) 2001,2002 the KPGP authors + See file libkdenetwork/AUTHORS.kpgp for details + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "keyselectiondialog.h" + +#include "keylistview.h" +#include "progressdialog.h" + +#include <kleo/dn.h> +#include <kleo/keylistjob.h> +#include <kleo/cryptobackendfactory.h> + +// gpgme++ +#include <gpgmepp/key.h> +#include <gpgmepp/keylistresult.h> + +// KDE +#include <klocale.h> +#include <kapplication.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kdebug.h> +#include <kwin.h> +#include <kconfig.h> +#include <kmessagebox.h> +#include <kprocess.h> + +// Qt +#include <qcheckbox.h> +#include <qtoolbutton.h> +#include <qlabel.h> +#include <qpixmap.h> +#include <qtimer.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qwhatsthis.h> +#include <qpopupmenu.h> +#include <qregexp.h> +#include <qpushbutton.h> + +#include <algorithm> +#include <iterator> + +#include <string.h> +#include <assert.h> + +static bool checkKeyUsage( const GpgME::Key & key, unsigned int keyUsage ) { + + if ( keyUsage & Kleo::KeySelectionDialog::ValidKeys ) { + if ( key.isInvalid() ) + kdDebug() << "key is invalid - ignoring" << endl; + if ( key.isExpired() ) { + kdDebug() << "key is expired" << endl; + return false; + } else if ( key.isRevoked() ) { + kdDebug() << "key is revoked" << endl; + return false; + } else if ( key.isDisabled() ) { + kdDebug() << "key is disabled" << endl; + return false; + } + } + + if ( keyUsage & Kleo::KeySelectionDialog::EncryptionKeys && + !key.canEncrypt() ) { + kdDebug() << "key can't encrypt" << endl; + return false; + } + if ( keyUsage & Kleo::KeySelectionDialog::SigningKeys && + !key.canSign() ) { + kdDebug() << "key can't sign" << endl; + return false; + } + if ( keyUsage & Kleo::KeySelectionDialog::CertificationKeys && + !key.canCertify() ) { + kdDebug() << "key can't certify" << endl; + return false; + } + if ( keyUsage & Kleo::KeySelectionDialog::AuthenticationKeys && + !key.canAuthenticate() ) { + kdDebug() << "key can't authenticate" << endl; + return false; + } + + if ( keyUsage & Kleo::KeySelectionDialog::SecretKeys && + !( keyUsage & Kleo::KeySelectionDialog::PublicKeys ) && + !key.isSecret() ) { + kdDebug() << "key isn't secret" << endl; + return false; + } + + if ( keyUsage & Kleo::KeySelectionDialog::TrustedKeys && + key.protocol() == GpgME::Context::OpenPGP && + // only check this for secret keys for now. + // Seems validity isn't checked for secret keylistings... + !key.isSecret() ) { + std::vector<GpgME::UserID> uids = key.userIDs(); + for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) + if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal ) + return true; + kdDebug() << "key has no UIDs with validity >= Marginal" << endl; + return false; + } + // X.509 keys are always trusted, else they won't be the keybox. + // PENDING(marc) check that this ^ is correct + + return true; +} + +static bool checkKeyUsage( const std::vector<GpgME::Key> & keys, unsigned int keyUsage ) { + for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) + if ( !checkKeyUsage( *it, keyUsage ) ) + return false; + return true; +} + +static inline QString time_t2string( time_t t ) { + QDateTime dt; + dt.setTime_t( t ); + return dt.toString(); +} + +namespace { + + class ColumnStrategy : public Kleo::KeyListView::ColumnStrategy { + public: + ColumnStrategy( unsigned int keyUsage ); + + QString title( int col ) const; + int width( int col, const QFontMetrics & fm ) const; + + QString text( const GpgME::Key & key, int col ) const; + QString toolTip( const GpgME::Key & key, int col ) const; + const QPixmap * pixmap( const GpgME::Key & key, int col ) const; + + private: + const QPixmap mKeyGoodPix, mKeyBadPix, mKeyUnknownPix, mKeyValidPix; + const unsigned int mKeyUsage; + }; + + ColumnStrategy::ColumnStrategy( unsigned int keyUsage ) + : Kleo::KeyListView::ColumnStrategy(), + mKeyGoodPix( UserIcon( "key_ok" ) ), + mKeyBadPix( UserIcon( "key_bad" ) ), + mKeyUnknownPix( UserIcon( "key_unknown" ) ), + mKeyValidPix( UserIcon( "key" ) ), + mKeyUsage( keyUsage ) + { + kdWarning( keyUsage == 0, 5150 ) + << "KeySelectionDialog: keyUsage == 0. You want to use AllKeys instead." << endl; + } + + QString ColumnStrategy::title( int col ) const { + switch ( col ) { + case 0: return i18n("Key ID"); + case 1: return i18n("User ID"); + default: return QString::null; + } + } + + int ColumnStrategy::width( int col, const QFontMetrics & fm ) const { + if ( col == 0 ) { + static const char hexchars[] = "0123456789ABCDEF"; + int maxWidth = 0; + for ( unsigned int i = 0 ; i < 16 ; ++i ) + maxWidth = kMax( fm.width( QChar( hexchars[i] ) ), maxWidth ); + return 8 * maxWidth + 2 * mKeyGoodPix.width(); + } + return Kleo::KeyListView::ColumnStrategy::width( col, fm ); + } + + QString ColumnStrategy::text( const GpgME::Key & key, int col ) const { + switch ( col ) { + case 0: + { + if ( key.shortKeyID() ) + return QString::fromUtf8( key.shortKeyID() ); + else + return i18n("<unknown>"); + } + break; + case 1: + { + const char * uid = key.userID(0).id(); + if ( key.protocol() == GpgME::Context::OpenPGP ) + return uid && *uid ? QString::fromUtf8( uid ) : QString::null ; + else // CMS + return Kleo::DN( uid ).prettyDN(); + } + break; + default: return QString::null; + } + } + + QString ColumnStrategy::toolTip( const GpgME::Key & key, int ) const { + const char * uid = key.userID(0).id(); + const char * fpr = key.primaryFingerprint(); + const char * issuer = key.issuerName(); + const GpgME::Subkey subkey = key.subkey(0); + const QString expiry = subkey.neverExpires() ? i18n("never") : time_t2string( subkey.expirationTime() ) ; + const QString creation = time_t2string( subkey.creationTime() ); + if ( key.protocol() == GpgME::Context::OpenPGP ) + return i18n( "OpenPGP key for %1\n" + "Created: %2\n" + "Expiry: %3\n" + "Fingerprint: %4" ) + .arg( uid ? QString::fromUtf8( uid ) : i18n("unknown"), + creation, expiry, + fpr ? QString::fromLatin1( fpr ) : i18n("unknown") ); + else + return i18n( "S/MIME key for %1\n" + "Created: %2\n" + "Expiry: %3\n" + "Fingerprint: %4\n" + "Issuer: %5" ) + .arg( uid ? Kleo::DN( uid ).prettyDN() : i18n("unknown"), + creation, expiry, + fpr ? QString::fromLatin1( fpr ) : i18n("unknown") ) + .arg( issuer ? Kleo::DN( issuer ).prettyDN() : i18n("unknown") ); + } + + const QPixmap * ColumnStrategy::pixmap( const GpgME::Key & key, int col ) const { + if ( col != 0 ) + return 0; + // this key did not undergo a validating keylisting yet: + if ( !( key.keyListMode() & GpgME::Context::Validate ) ) + return &mKeyUnknownPix; + + if ( !checkKeyUsage( key, mKeyUsage ) ) + return &mKeyBadPix; + + if ( key.protocol() == GpgME::Context::CMS ) + return &mKeyGoodPix; + + switch ( key.userID(0).validity() ) { + default: + case GpgME::UserID::Unknown: + case GpgME::UserID::Undefined: + return &mKeyUnknownPix; + case GpgME::UserID::Never: + return &mKeyValidPix; + case GpgME::UserID::Marginal: + case GpgME::UserID::Full: + case GpgME::UserID::Ultimate: + return &mKeyGoodPix; + } + } + +} + + +static const int sCheckSelectionDelay = 250; + +Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title, + const QString & text, + const std::vector<GpgME::Key> & selectedKeys, + unsigned int keyUsage, + bool extendedSelection, + bool rememberChoice, + QWidget * parent, const char * name, + bool modal ) + : KDialogBase( parent, name, modal, title, Default|Ok|Cancel|Help, Ok ), + mOpenPGPBackend( 0 ), + mSMIMEBackend( 0 ), + mRememberCB( 0 ), + mSelectedKeys( selectedKeys ), + mKeyUsage( keyUsage ), + mCurrentContextMenuItem( 0 ) +{ + init( rememberChoice, extendedSelection, text, QString::null ); +} + +Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title, + const QString & text, + const QString & initialQuery, + unsigned int keyUsage, + bool extendedSelection, + bool rememberChoice, + QWidget * parent, const char * name, + bool modal ) + : KDialogBase( parent, name, modal, title, Default|Ok|Cancel|Help, Ok ), + mOpenPGPBackend( 0 ), + mSMIMEBackend( 0 ), + mRememberCB( 0 ), + mKeyUsage( keyUsage ), + mSearchText( initialQuery ), + mCurrentContextMenuItem( 0 ) +{ + init( rememberChoice, extendedSelection, text, initialQuery ); +} + +void Kleo::KeySelectionDialog::init( bool rememberChoice, bool extendedSelection, + const QString & text, const QString & initialQuery ) { + if ( mKeyUsage & OpenPGPKeys ) + mOpenPGPBackend = Kleo::CryptoBackendFactory::instance()->openpgp(); + if ( mKeyUsage & SMIMEKeys ) + mSMIMEBackend = Kleo::CryptoBackendFactory::instance()->smime(); + + mCheckSelectionTimer = new QTimer( this ); + mStartSearchTimer = new QTimer( this ); + + QFrame *page = makeMainWidget(); + mTopLayout = new QVBoxLayout( page, 0, spacingHint() ); + + if ( !text.isEmpty() ) { + QLabel* textLabel = new QLabel( text, page ); + textLabel->setAlignment( textLabel->alignment() | Qt::WordBreak ); + mTopLayout->addWidget( textLabel ); + } + + QHBoxLayout * hlay = new QHBoxLayout( mTopLayout ); // inherits spacing + QLineEdit * le = new QLineEdit( page ); + le->setText( initialQuery ); + QToolButton *clearButton = new QToolButton( page ); + clearButton->setIconSet( KGlobal::iconLoader()->loadIconSet( + KApplication::reverseLayout() ? "clear_left":"locationbar_erase", KIcon::Small, 0 ) ); + hlay->addWidget( clearButton ); + hlay->addWidget( new QLabel( le, i18n("&Search for:"), page ) ); + hlay->addWidget( le, 1 ); + le->setFocus(); + + connect( clearButton, SIGNAL( clicked() ), le, SLOT( clear() ) ); + connect( le, SIGNAL(textChanged(const QString&)), + this, SLOT(slotSearch(const QString&)) ); + connect( mStartSearchTimer, SIGNAL(timeout()), SLOT(slotFilter()) ); + + mKeyListView = new KeyListView( new ColumnStrategy( mKeyUsage ), 0, page, "mKeyListView" ); + mKeyListView->setResizeMode( QListView::LastColumn ); + mKeyListView->setRootIsDecorated( true ); + mKeyListView->setShowSortIndicator( true ); + mKeyListView->setSorting( 1, true ); // sort by User ID + mKeyListView->setShowToolTips( true ); + if ( extendedSelection ) + mKeyListView->setSelectionMode( QListView::Extended ); + mTopLayout->addWidget( mKeyListView, 10 ); + + if ( rememberChoice ) { + mRememberCB = new QCheckBox( i18n("&Remember choice"), page ); + mTopLayout->addWidget( mRememberCB ); + QWhatsThis::add( mRememberCB, + i18n("<qt><p>If you check this box your choice will " + "be stored and you will not be asked again." + "</p></qt>") ); + } + + connect( mCheckSelectionTimer, SIGNAL(timeout()), + SLOT(slotCheckSelection()) ); + connectSignals(); + + connect( mKeyListView, + SIGNAL(doubleClicked(Kleo::KeyListViewItem*,const QPoint&,int)), + SLOT(slotTryOk()) ); + connect( mKeyListView, + SIGNAL(contextMenu(Kleo::KeyListViewItem*,const QPoint&)), + SLOT(slotRMB(Kleo::KeyListViewItem*,const QPoint&)) ); + + setButtonText( KDialogBase::Default, i18n("&Reread Keys") ); + setButtonGuiItem( KDialogBase::Help, i18n("&Start Certificate Manager") ); + connect( this, SIGNAL(defaultClicked()), this, SLOT(slotRereadKeys()) ); + connect( this, SIGNAL(helpClicked()), this, SLOT(slotStartCertificateManager()) ); + + slotRereadKeys(); + mTopLayout->activate(); + + if ( kapp ) { + KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() ); + QSize dialogSize( 500, 400 ); + + KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" ); + dialogSize = dialogConfig.readSizeEntry( "Dialog size", &dialogSize ); + resize( dialogSize ); + } +} + +Kleo::KeySelectionDialog::~KeySelectionDialog() { + KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" ); + dialogConfig.writeEntry( "Dialog size", size() ); + dialogConfig.sync(); +} + + +void Kleo::KeySelectionDialog::connectSignals() { + if ( mKeyListView->isMultiSelection() ) + connect( mKeyListView, SIGNAL(selectionChanged()), + SLOT(slotSelectionChanged()) ); + else + connect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)), + SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) ); +} + +void Kleo::KeySelectionDialog::disconnectSignals() { + if ( mKeyListView->isMultiSelection() ) + disconnect( mKeyListView, SIGNAL(selectionChanged()), + this, SLOT(slotSelectionChanged()) ); + else + disconnect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)), + this, SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) ); +} + +const GpgME::Key & Kleo::KeySelectionDialog::selectedKey() const { + if ( mKeyListView->isMultiSelection() || !mKeyListView->selectedItem() ) + return GpgME::Key::null; + return mKeyListView->selectedItem()->key(); +} + +QString Kleo::KeySelectionDialog::fingerprint() const { + return selectedKey().primaryFingerprint(); +} + +QStringList Kleo::KeySelectionDialog::fingerprints() const { + QStringList result; + for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it ) + if ( const char * fpr = it->primaryFingerprint() ) + result.push_back( fpr ); + return result; +} + +QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const { + QStringList result; + for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it ) + if ( it->protocol() == GpgME::Context::OpenPGP ) + if ( const char * fpr = it->primaryFingerprint() ) + result.push_back( fpr ); + return result; +} + +QStringList Kleo::KeySelectionDialog::smimeFingerprints() const { + QStringList result; + for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it ) + if ( it->protocol() == GpgME::Context::CMS ) + if ( const char * fpr = it->primaryFingerprint() ) + result.push_back( fpr ); + return result; +} + +void Kleo::KeySelectionDialog::slotRereadKeys() { + mKeyListView->clear(); + mListJobCount = 0; + mTruncated = 0; + mSavedOffsetY = mKeyListView->contentsY(); + + disconnectSignals(); + mKeyListView->setEnabled( false ); + + // FIXME: save current selection + if ( mOpenPGPBackend ) + startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false /*non-validating*/ ); + if ( mSMIMEBackend ) + startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false /*non-validating*/ ); + + if ( mListJobCount == 0 ) { + mKeyListView->setEnabled( true ); + KMessageBox::information( this, + i18n("No backends found for listing keys. " + "Check your installation."), + i18n("Key Listing Failed") ); + connectSignals(); + } +} + +void Kleo::KeySelectionDialog::slotHelp() +{ + emit helpClicked(); +} + +void Kleo::KeySelectionDialog::slotStartCertificateManager() +{ + KProcess certManagerProc; + certManagerProc << "kleopatra"; + + if( !certManagerProc.start( KProcess::DontCare ) ) + KMessageBox::error( this, i18n( "Could not start certificate manager; " + "please check your installation." ), + i18n( "Certificate Manager Error" ) ); + else + kdDebug(5006) << "\nslotStartCertManager(): certificate manager started.\n" << endl; +} + +#ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ +#define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ +static void showKeyListError( QWidget * parent, const GpgME::Error & err ) { + assert( err ); + const QString msg = i18n( "<qt><p>An error occurred while fetching " + "the keys from the backend:</p>" + "<p><b>%1</b></p></qt>" ) + .arg( QString::fromLocal8Bit( err.asString() ) ); + + KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) ); +} +#endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ + +namespace { + struct ExtractFingerprint { + QString operator()( const GpgME::Key & key ) { + return key.primaryFingerprint(); + } + }; +} + +void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) { + assert( backend ); + KeyListJob * job = backend->keyListJob( false, false, validate ); // local, w/o sigs, validation as givem + if ( !job ) + return; + + connect( job, SIGNAL(result(const GpgME::KeyListResult&)), + SLOT(slotKeyListResult(const GpgME::KeyListResult&)) ); + connect( job, SIGNAL(nextKey(const GpgME::Key&)), + mKeyListView, validate ? + SLOT(slotRefreshKey(const GpgME::Key&)) : + SLOT(slotAddKey(const GpgME::Key&)) ); + + QStringList fprs; + std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() ); + const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) ); + + if ( err ) + return showKeyListError( this, err ); + + // FIXME: create a MultiProgressDialog: + (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this ); + ++mListJobCount; +} + +static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) { + klv->clearSelection(); + if ( selectedKeys.empty() ) + return; + for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it ) + if ( Kleo::KeyListViewItem * item = klv->itemByFingerprint( it->primaryFingerprint() ) ) + item->setSelected( true ); +} + +void Kleo::KeySelectionDialog::slotKeyListResult( const GpgME::KeyListResult & res ) { + if ( res.error() ) + showKeyListError( this, res.error() ); + else if ( res.isTruncated() ) + ++mTruncated; + + if ( --mListJobCount > 0 ) + return; // not yet finished... + + if ( mTruncated > 0 ) + KMessageBox::information( this, + i18n("<qt>One backend returned truncated output.<br>" + "Not all available keys are shown</qt>", + "<qt>%n backends returned truncated output.<br>" + "Not all available keys are shown</qt>", + mTruncated), + i18n("Key List Result") ); + + mKeyListView->flushKeys(); + + mKeyListView->setEnabled( true ); + mListJobCount = mTruncated = 0; + mKeysToCheck.clear(); + + selectKeys( mKeyListView, mSelectedKeys ); + + slotFilter(); + + connectSignals(); + + slotSelectionChanged(); + + // restore the saved position of the contents + mKeyListView->setContentsPos( 0, mSavedOffsetY ); mSavedOffsetY = 0; +} + +void Kleo::KeySelectionDialog::slotSelectionChanged() { + kdDebug(5150) << "KeySelectionDialog::slotSelectionChanged()" << endl; + + // (re)start the check selection timer. Checking the selection is delayed + // because else drag-selection doesn't work very good (checking key trust + // is slow). + mCheckSelectionTimer->start( sCheckSelectionDelay ); +} + +namespace { + struct AlreadyChecked { + bool operator()( const GpgME::Key & key ) const { + return key.keyListMode() & GpgME::Context::Validate ; + } + }; +} + +void Kleo::KeySelectionDialog::slotCheckSelection( KeyListViewItem * item ) { + kdDebug(5150) << "KeySelectionDialog::slotCheckSelection()\n"; + + mCheckSelectionTimer->stop(); + + mSelectedKeys.clear(); + + if ( !mKeyListView->isMultiSelection() ) { + if ( item ) + mSelectedKeys.push_back( item->key() ); + } + + for ( KeyListViewItem * it = mKeyListView->firstChild() ; it ; it = it->nextSibling() ) + if ( it->isSelected() ) + mSelectedKeys.push_back( it->key() ); + + mKeysToCheck.clear(); + std::remove_copy_if( mSelectedKeys.begin(), mSelectedKeys.end(), + std::back_inserter( mKeysToCheck ), + AlreadyChecked() ); + if ( mKeysToCheck.empty() ) { + enableButtonOK( !mSelectedKeys.empty() && + checkKeyUsage( mSelectedKeys, mKeyUsage ) ); + return; + } + + // performed all fast checks - now for validating key listing: + startValidatingKeyListing(); +} + +void Kleo::KeySelectionDialog::startValidatingKeyListing() { + if ( mKeysToCheck.empty() ) + return; + + mListJobCount = 0; + mTruncated = 0; + mSavedOffsetY = mKeyListView->contentsY(); + + disconnectSignals(); + mKeyListView->setEnabled( false ); + + std::vector<GpgME::Key> smime, openpgp; + for ( std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin() ; it != mKeysToCheck.end() ; ++it ) + if ( it->protocol() == GpgME::Context::OpenPGP ) + openpgp.push_back( *it ); + else + smime.push_back( *it ); + + if ( !openpgp.empty() ) { + assert( mOpenPGPBackend ); + startKeyListJobForBackend( mOpenPGPBackend, openpgp, true /*validate*/ ); + } + if ( !smime.empty() ) { + assert( mSMIMEBackend ); + startKeyListJobForBackend( mSMIMEBackend, smime, true /*validate*/ ); + } + + assert( mListJobCount > 0 ); +} + +bool Kleo::KeySelectionDialog::rememberSelection() const { + return mRememberCB && mRememberCB->isChecked() ; +} + +void Kleo::KeySelectionDialog::slotRMB( Kleo::KeyListViewItem * item, const QPoint & p ) { + if ( !item ) return; + + mCurrentContextMenuItem = item; + + QPopupMenu menu; + menu.insertItem( i18n( "Recheck Key" ), this, SLOT(slotRecheckKey()) ); + menu.exec( p ); +} + +void Kleo::KeySelectionDialog::slotRecheckKey() { + if ( !mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull() ) + return; + + mKeysToCheck.clear(); + mKeysToCheck.push_back( mCurrentContextMenuItem->key() ); +} + +void Kleo::KeySelectionDialog::slotTryOk() { + if ( actionButton( Ok )->isEnabled() ) + slotOk(); +} + +void Kleo::KeySelectionDialog::slotOk() { + if ( mCheckSelectionTimer->isActive() ) + slotCheckSelection(); + // button could be disabled again after checking the selected key + if ( !actionButton( Ok )->isEnabled() ) + return; + mStartSearchTimer->stop(); + accept(); +} + + +void Kleo::KeySelectionDialog::slotCancel() { + mCheckSelectionTimer->stop(); + mStartSearchTimer->stop(); + reject(); +} + +void Kleo::KeySelectionDialog::slotSearch( const QString & text ) { + mSearchText = text.stripWhiteSpace().upper(); + slotSearch(); +} + +void Kleo::KeySelectionDialog::slotSearch() { + mStartSearchTimer->start( sCheckSelectionDelay, true /*single-shot*/ ); +} + +void Kleo::KeySelectionDialog::slotFilter() { + if ( mSearchText.isEmpty() ) { + showAllItems(); + return; + } + + // OK, so we need to filter: + QRegExp keyIdRegExp( "(?:0x)?[A-F0-9]{1,8}", false /*case-insens.*/ ); + if ( keyIdRegExp.exactMatch( mSearchText ) ) { + if ( mSearchText.startsWith( "0X" ) ) + // search for keyID only: + filterByKeyID( mSearchText.mid( 2 ) ); + else + // search for UID and keyID: + filterByKeyIDOrUID( mSearchText ); + } else { + // search in UID: + filterByUID( mSearchText ); + } +} + +void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) { + assert( keyID.length() <= 8 ); + assert( !keyID.isEmpty() ); // regexp in slotFilter should prevent these + if ( keyID.isEmpty() ) + showAllItems(); + else + for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() ) + item->setVisible( item->text( 0 ).upper().startsWith( keyID ) ); +} + +static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) { + if ( !item ) + return false; + + const std::vector<GpgME::UserID> uids = item->key().userIDs(); + for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) + if ( it->id() && rx.search( QString::fromUtf8( it->id() ) ) >= 0 ) + return true; + return false; +} + +void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const QString & str ) { + assert( !str.isEmpty() ); + + // match beginnings of words: + QRegExp rx( "\\b" + QRegExp::escape( str ), false ); + + for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() ) + item->setVisible( item->text( 0 ).upper().startsWith( str ) || anyUIDMatches( item, rx ) ); + +} + +void Kleo::KeySelectionDialog::filterByUID( const QString & str ) { + assert( !str.isEmpty() ); + + // match beginnings of words: + QRegExp rx( "\\b" + QRegExp::escape( str ), false ); + + for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() ) + item->setVisible( anyUIDMatches( item, rx ) ); +} + + +void Kleo::KeySelectionDialog::showAllItems() { + for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() ) + item->setVisible( true ); +} + +#include "keyselectiondialog.moc" diff --git a/certmanager/lib/ui/keyselectiondialog.h b/certmanager/lib/ui/keyselectiondialog.h new file mode 100644 index 000000000..f274398b1 --- /dev/null +++ b/certmanager/lib/ui/keyselectiondialog.h @@ -0,0 +1,179 @@ +/* -*- c++ -*- + keyselectiondialog.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarävdalens Datakonsult AB + + Based on kpgpui.h + Copyright (C) 2001,2002 the KPGP authors + See file libkdenetwork/AUTHORS.kpgp for details + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifndef __KLEO_UI_KEYSELECTIONDIALOG_H__ +#define __KLEO_UI_KEYSELECTIONDIALOG_H__ + +#include <kdialogbase.h> + +#include <kleo/cryptobackend.h> +#include <gpgmepp/key.h> +#include <kdepimmacros.h> +#include <vector> + +class QVBoxLayout; +class QCheckBox; +class QPixmap; +class QTimer; +class QListViewItem; +class QRegExp; +class QPoint; + +namespace Kleo { + class KeyListView; + class KeyListViewItem; +} + +namespace GpgME { + class KeyListResult; +} + +namespace Kleo { + + class KDE_EXPORT KeySelectionDialog : public KDialogBase { + Q_OBJECT + public: + + enum KeyUsage { + PublicKeys = 1, + SecretKeys = 2, + EncryptionKeys = 4, + SigningKeys = 8, + ValidKeys = 16, + TrustedKeys = 32, + CertificationKeys = 64, + AuthenticationKeys = 128, + OpenPGPKeys = 256, + SMIMEKeys = 512, + AllKeys = PublicKeys | SecretKeys | OpenPGPKeys | SMIMEKeys, + ValidEncryptionKeys = AllKeys | EncryptionKeys | ValidKeys, + ValidTrustedEncryptionKeys = AllKeys | EncryptionKeys | ValidKeys | TrustedKeys + }; + + KeySelectionDialog( const QString & title, + const QString & text, + const std::vector<GpgME::Key> & selectedKeys=std::vector<GpgME::Key>(), + unsigned int keyUsage=AllKeys, + bool extendedSelection=false, + bool rememberChoice=false, + QWidget * parent=0, const char * name=0, + bool modal=true ); + KeySelectionDialog( const QString & title, + const QString & text, + const QString & initialPattern, + unsigned int keyUsage=AllKeys, + bool extendedSelection=false, + bool rememberChoice=false, + QWidget * parent=0, const char * name=0, + bool modal=true ); + ~KeySelectionDialog(); + + /** Returns the key ID of the selected key in single selection mode. + Otherwise it returns a null key. */ + const GpgME::Key & selectedKey() const; + + QString fingerprint() const; + + /** Returns a list of selected key IDs. */ + const std::vector<GpgME::Key> & selectedKeys() const { return mSelectedKeys; } + + /// Return all the selected fingerprints + QStringList fingerprints() const; + + /// Return the selected openpgp fingerprints + QStringList pgpKeyFingerprints() const; + /// Return the selected smime fingerprints + QStringList smimeFingerprints() const; + + bool rememberSelection() const; + protected slots: + // reimplemented to avoid popping up the help, since we + // override the button + void slotHelp(); + + // Could be used by derived classes to insert their own widget + QVBoxLayout* topLayout() const { return mTopLayout; } + + private slots: + void slotRereadKeys(); + void slotStartCertificateManager(); + void slotKeyListResult( const GpgME::KeyListResult & ); + void slotSelectionChanged(); + void slotCheckSelection() { slotCheckSelection( 0 ); } + void slotCheckSelection( Kleo::KeyListViewItem * ); + void slotRMB( Kleo::KeyListViewItem *, const QPoint & ); + void slotRecheckKey(); + void slotTryOk(); + void slotOk(); + void slotCancel(); + void slotSearch( const QString & text ); + void slotSearch(); + void slotFilter(); + + private: + void filterByKeyID( const QString & keyID ); + void filterByKeyIDOrUID( const QString & keyID ); + void filterByUID( const QString & uid ); + void showAllItems(); + bool anyChildMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) const; + + void connectSignals(); + void disconnectSignals(); + + void startKeyListJobForBackend( const Kleo::CryptoBackend::Protocol *, const std::vector<GpgME::Key> &, bool ); + void startValidatingKeyListing(); + + void init( bool, bool, const QString &, const QString & ); + + private: + QVBoxLayout* mTopLayout; + Kleo::KeyListView * mKeyListView; + const Kleo::CryptoBackend::Protocol * mOpenPGPBackend; + const Kleo::CryptoBackend::Protocol * mSMIMEBackend; + QCheckBox * mRememberCB; + std::vector<GpgME::Key> mSelectedKeys, mKeysToCheck; + unsigned int mKeyUsage; + QTimer * mCheckSelectionTimer; + QTimer * mStartSearchTimer; + // cross-eventloop temporaries: + QString mSearchText; + Kleo::KeyListViewItem * mCurrentContextMenuItem; + int mTruncated, mListJobCount, mSavedOffsetY; + }; + +} + +#endif // __KLEO_UI_KEYSELECTIONDIALOG_H__ diff --git a/certmanager/lib/ui/messagebox.cpp b/certmanager/lib/ui/messagebox.cpp new file mode 100644 index 000000000..283d33108 --- /dev/null +++ b/certmanager/lib/ui/messagebox.cpp @@ -0,0 +1,265 @@ +/* + messagebox.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "messagebox.h" + +#include "kleo/job.h" + +#include <gpgmepp/signingresult.h> +#include <gpgmepp/encryptionresult.h> + +#include <kfiledialog.h> +#include <kdialogbase.h> +#include <klocale.h> +#include <ksavefile.h> +#include <kguiitem.h> + +#include <qtextedit.h> +#include <qtextstream.h> +#include <qvbox.h> + +using namespace Kleo; +using namespace GpgME; + +namespace { + +static KGuiItem KGuiItem_save() { + return KGuiItem( i18n("&Save to Disk..."), "filesaveas" ); +} + +static KGuiItem KGuiItem_copy() { + return KGuiItem( i18n("&Copy to Clipboard"), "editcopy", i18n("Copy Audit Log to Clipboard") ); +} + +static KGuiItem KGuiItem_showAuditLog() { + return KGuiItem( i18n("&Show Audit Log") ); // "view_log"? +} + +class AuditLogViewer : public KDialogBase { + // Q_OBJECT +public: + explicit AuditLogViewer( const QString & log, QWidget * parent=0, const char * name=0, WFlags f=0 ) + : KDialogBase( parent, name, false, i18n("View GnuPG Audit Log"), + Close|User1|User2, Close, false, KGuiItem_save(), KGuiItem_copy() ), + m_textEdit( new QTextEdit( this, "m_textEdit" ) ) + { + setWFlags( f ); + setMainWidget( m_textEdit ); + m_textEdit->setTextFormat( QTextEdit::RichText ); + m_textEdit->setReadOnly( true ); + setAuditLog( log ); + } + ~AuditLogViewer() {} + + void setAuditLog( const QString & log ) { + m_textEdit->setText( log ); + } + +private: + void slotUser1() { + const QString fileName = KFileDialog::getSaveFileName( QString(), QString(), + this, i18n("Choose File to Save GnuPG Audit Log to") ); + if ( fileName.isEmpty() ) + return; + + KSaveFile file( fileName ); + + if ( QTextStream * const s = file.textStream() ) { + *s << m_textEdit->text() << endl; + file.close(); + } + + if ( const int err = file.status() ) + KMessageBox::error( this, i18n("Couldn't save to file \"%1\": %2") + .arg( file.name(), QString::fromLocal8Bit( strerror( err ) ) ), + i18n("File Save Error") ); + } + void slotUser2() { + m_textEdit->selectAll(); + m_textEdit->copy(); + m_textEdit->selectAll( false ); + } + +private: + QTextEdit * m_textEdit; +}; + +} // anon namespace + +// static +void MessageBox::auditLog( QWidget * parent, const Job * job, const QString & caption ) { + + if ( !job ) + return; + + if ( !GpgME::hasFeature( AuditLogFeature ) ) { + KMessageBox::information( parent, i18n("Your system does not have support for GnuPG Audit Logs"), + i18n("System Error") ); + return; + } + + const QString log = job->auditLogAsHtml(); + if ( log.isEmpty() ) { + KMessageBox::information( parent, i18n("No GnuPG Audit Log available for this operation."), + i18n("No GnuPG Audit Log") ); + return; + } + + auditLog( parent, log, caption ); +} + +// static +void MessageBox::auditLog( QWidget * parent, const QString & log, const QString & caption ) { + AuditLogViewer * const alv = new AuditLogViewer( "<qt>" + log + "</qt>", parent, "alv", Qt::WDestructiveClose ); + alv->setCaption( caption ); + alv->show(); +} + +// static +void MessageBox::auditLog( QWidget * parent, const Job * job ) { + auditLog( parent, job, i18n("GnuPG Audit Log Viewer") ); +} + +// static +void MessageBox::auditLog( QWidget * parent, const QString & log ) { + auditLog( parent, log, i18n("GnuPG Audit Log Viewer") ); +} + +static QString to_information_string( const SigningResult & result ) { + return result.error() + ? i18n("Signing failed: %1").arg( QString::fromLocal8Bit( result.error().asString() ) ) + : i18n("Signing successful") ; +} + +static QString to_error_string( const SigningResult & result ) { + return to_information_string( result ); +} + +static QString to_information_string( const EncryptionResult & result ) { + return result.error() + ? i18n("Encryption failed: %1").arg( QString::fromLocal8Bit( result.error().asString() ) ) + : i18n("Encryption successful") ; +} + +static QString to_error_string( const EncryptionResult & result ) { + return to_information_string( result ); +} + +static QString to_information_string( const SigningResult & sresult, const EncryptionResult & eresult ) { + return to_information_string( sresult ) + '\n' + to_information_string( eresult ); +} + +static QString to_error_string( const SigningResult & sresult, const EncryptionResult & eresult ) { + return to_information_string( sresult, eresult ); +} + +// static +void MessageBox::information( QWidget * parent, const SigningResult & result, const Job * job, int options ) { + information( parent, result, job, i18n("Signing Result"), options ); +} + +// static +void MessageBox::information( QWidget * parent, const SigningResult & result, const Job * job, const QString & caption, int options ) { + make( parent, QMessageBox::Information, to_information_string( result ), job, caption, options ); +} + +// static +void MessageBox::error( QWidget * parent, const SigningResult & result, const Job * job, int options ) { + error( parent, result, job, i18n("Signing Error"), options ); +} + +// static +void MessageBox::error( QWidget * parent, const SigningResult & result, const Job * job, const QString & caption, int options ) { + make( parent, QMessageBox::Critical, to_error_string( result ), job, caption, options ); +} + +// static +void MessageBox::information( QWidget * parent, const EncryptionResult & result, const Job * job, int options ) { + information( parent, result, job, i18n("Encryption Result"), options ); +} + +// static +void MessageBox::information( QWidget * parent, const EncryptionResult & result, const Job * job, const QString & caption, int options ) { + make( parent, QMessageBox::Information, to_information_string( result ), job, caption, options ); +} + +// static +void MessageBox::error( QWidget * parent, const EncryptionResult & result, const Job * job, int options ) { + error( parent, result, job, i18n("Encryption Error"), options ); +} + +// static +void MessageBox::error( QWidget * parent, const EncryptionResult & result, const Job * job, const QString & caption, int options ) { + make( parent, QMessageBox::Critical, to_error_string( result ), job, caption, options ); +} + +// static +void MessageBox::information( QWidget * parent, const SigningResult & sresult, const EncryptionResult & eresult, const Job * job, int options ) { + information( parent, sresult, eresult, job, i18n("Encryption Result"), options ); +} + +// static +void MessageBox::information( QWidget * parent, const SigningResult & sresult, const EncryptionResult & eresult, const Job * job, const QString & caption, int options ) { + make( parent, QMessageBox::Information, to_information_string( sresult, eresult ), job, caption, options ); +} + +// static +void MessageBox::error( QWidget * parent, const SigningResult & sresult, const EncryptionResult & eresult, const Job * job, int options ) { + error( parent, sresult, eresult, job, i18n("Encryption Error"), options ); +} + +// static +void MessageBox::error( QWidget * parent, const SigningResult & sresult, const EncryptionResult & eresult, const Job * job, const QString & caption, int options ) { + make( parent, QMessageBox::Critical, to_error_string( sresult, eresult ), job, caption, options ); +} + +// static +void MessageBox::make( QWidget * parent, QMessageBox::Icon icon, const QString & text, const Job * job, const QString & caption, int options ) { + KDialogBase * dialog = GpgME::hasFeature( GpgME::AuditLogFeature ) + ? new KDialogBase( caption, KDialogBase::Yes | KDialogBase::No, + KDialogBase::Yes, KDialogBase::Yes, + parent, "error", true, true, + KStdGuiItem::ok(), KGuiItem_showAuditLog() ) + : new KDialogBase( caption, KDialogBase::Yes, + KDialogBase::Yes, KDialogBase::Yes, + parent, "error", true, true, + KStdGuiItem::ok() ) ; + if ( options & KMessageBox::PlainCaption ) + dialog->setPlainCaption( caption ); + + if ( KDialogBase::No == KMessageBox::createKMessageBox( dialog, icon, text, QStringList(), QString::null, 0, options ) ) + auditLog( 0, job ); +} diff --git a/certmanager/lib/ui/messagebox.h b/certmanager/lib/ui/messagebox.h new file mode 100644 index 000000000..a84f86e11 --- /dev/null +++ b/certmanager/lib/ui/messagebox.h @@ -0,0 +1,83 @@ +/* + messagebox.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2007 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifndef __KLEO_UI_MESSAGEBOX_H__ +#define __KLEO_UI_MESSAGEBOX_H__ + +#include <kmessagebox.h> + +namespace GpgME { + class SigningResult; + class EncryptionResult; + class DecryptionResult; + class VerificationResult; +} + +namespace Kleo { + class Job; +} + +class QWidget; +class QString; + +namespace Kleo { + + class MessageBox { + public: + static void information( QWidget * parent, const GpgME::SigningResult & result, const Kleo::Job * job, const QString & caption, int options=KMessageBox::Notify ); + static void information( QWidget * parent, const GpgME::SigningResult & result, const Kleo::Job * job, int options=KMessageBox::Notify ); + static void error( QWidget * parent, const GpgME::SigningResult & result, const Kleo::Job * job, const QString & caption, int options=KMessageBox::Notify ); + static void error( QWidget * parent, const GpgME::SigningResult & result, const Kleo::Job * job, int options=KMessageBox::Notify ); + + static void information( QWidget * parent, const GpgME::EncryptionResult & result, const Kleo::Job * job, const QString & caption, int options=KMessageBox::Notify ); + static void information( QWidget * parent, const GpgME::EncryptionResult & result, const Kleo::Job * job, int options=KMessageBox::Notify ); + static void error( QWidget * parent, const GpgME::EncryptionResult & result, const Kleo::Job * job, const QString & caption, int options=KMessageBox::Notify ); + static void error( QWidget * parent, const GpgME::EncryptionResult & result, const Kleo::Job * job, int options=KMessageBox::Notify ); + + static void information( QWidget * parent, const GpgME::SigningResult & sresult, const GpgME::EncryptionResult & eresult, const Kleo::Job * job, const QString & caption, int options=KMessageBox::Notify ); + static void information( QWidget * parent, const GpgME::SigningResult & sresult, const GpgME::EncryptionResult & eresult, const Kleo::Job * job, int options=KMessageBox::Notify ); + static void error( QWidget * parent, const GpgME::SigningResult & sresult, const GpgME::EncryptionResult & eresult, const Kleo::Job * job, const QString & caption, int options=KMessageBox::Notify ); + static void error( QWidget * parent, const GpgME::SigningResult & sresult, const GpgME::EncryptionResult & eresult, const Kleo::Job * job, int options=KMessageBox::Notify ); + + static void auditLog( QWidget * parent, const Kleo::Job * job, const QString & caption ); + static void auditLog( QWidget * parent, const Kleo::Job * job ); + static void auditLog( QWidget * parent, const QString & log, const QString & caption ); + static void auditLog( QWidget * parent, const QString & log ); + + private: + static void make( QWidget * parent, QMessageBox::Icon icon, const QString & text, const Kleo::Job * job, const QString & caption, int options ); + }; + + +} + +#endif /* __KLEO_UI_MESSAGEBOX_H__ */ diff --git a/certmanager/lib/ui/passphrasedialog.cpp b/certmanager/lib/ui/passphrasedialog.cpp new file mode 100644 index 000000000..5915387f5 --- /dev/null +++ b/certmanager/lib/ui/passphrasedialog.cpp @@ -0,0 +1,123 @@ +/* -*- c++ -*- + passphrasedialog.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. + + + Based on kpgpui.cpp + Copyright (C) 2001,2002 the KPGP authors + See file libkdenetwork/AUTHORS.kpgp for details + + This file is part of KPGP, the KDE PGP/GnuPG support library. + + KPGP 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. + + 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 +*/ + +#ifndef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "passphrasedialog.h" + +#include <kpassdlg.h> +#include <kiconloader.h> +#include <klocale.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qfontmetrics.h> + +struct Kleo::PassphraseDialog::Private { + KPasswordEdit * lineedit; +}; + + +Kleo::PassphraseDialog::PassphraseDialog( const QString & msg, const QString & caption, + QWidget * parent, const char * name, bool modal ) + : KDialogBase( parent, name, modal, caption, Ok|Cancel, Ok ), d( 0 ) +{ + d = new Private(); + + QWidget * w = new QWidget( this ); + setMainWidget( w ); + + QHBoxLayout * hlay = new QHBoxLayout( w, 0, spacingHint() ); + + QLabel * label = new QLabel( w ); + label->setPixmap( DesktopIcon( "pgp-keys", KIcon::SizeMedium ) ); + hlay->addWidget( label, 0, AlignTop ); + + QVBoxLayout * vlay = new QVBoxLayout( hlay ); // inherits spacing + + vlay->addWidget( new QLabel( msg.isEmpty() ? i18n("Please enter your passphrase:") : msg, w ) ); + + d->lineedit = new KPasswordEdit( KPasswordEdit::OneStar, w, "d->lineedit" ); + d->lineedit->setMinimumWidth( fontMetrics().width("*") * 20 ); + d->lineedit->setFocus(); + + vlay->addWidget( d->lineedit ); + + connect( d->lineedit, SIGNAL(returnPressed()), SLOT(slotOk()) ); + + disableResize(); +} + + +Kleo::PassphraseDialog::~PassphraseDialog() { + delete d; d = 0; +} + +const char * Kleo::PassphraseDialog::passphrase() const { + return d->lineedit->password(); +} + +void Kleo::PassphraseDialog::slotOk() { + const char * pass = passphrase(); + emit finished( pass ? pass : "" ); + KDialogBase::slotOk(); +} + +void Kleo::PassphraseDialog::slotCancel() { + emit canceled(); + KDialogBase::slotCancel(); +} + + +void Kleo::PassphraseDialog::virtual_hook( int id, void * data ) { + return KDialogBase::virtual_hook( id, data ); +} + +#include "passphrasedialog.moc" diff --git a/certmanager/lib/ui/passphrasedialog.h b/certmanager/lib/ui/passphrasedialog.h new file mode 100644 index 000000000..12a434e13 --- /dev/null +++ b/certmanager/lib/ui/passphrasedialog.h @@ -0,0 +1,91 @@ +/* -*- c++ -*- + passphrasedialog.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. + + + Based on kpgpui.h + Copyright (C) 2001,2002 the KPGP authors + See file libkdenetwork/AUTHORS.kpgp for details + + This file is part of KPGP, the KDE PGP/GnuPG support library. + + KPGP 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. + + 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 +*/ + +#ifndef __KLEO_UI_PASSPHRASEDIALOG_H__ +#define __KLEO_UI_PASSPHRASEDIALOG_H__ + +#include <kdialogbase.h> + +namespace Kleo { + + class PassphraseDialog : public KDialogBase { + Q_OBJECT + public: + PassphraseDialog( const QString & description, + const QString & caption=QString::null, + QWidget * parent=0, const char * name=0, + bool modal=true ); + ~PassphraseDialog(); + + const char * passphrase() const; + + signals: + /** emitted when the user clicks Ok. \a pass is never NULL. + \c pass only valid inside slots connected to this signal. + */ + void finished( const char * pass ); + /** emitted when the user clicks Cancel. */ + void canceled(); + + protected slots: + /*! \reimp */ + void slotOk(); + /*! \reimp */ + void slotCancel(); + + private: + class Private; + Private * d; + protected: + /*! \reimp */ + void virtual_hook( int, void* ); + }; + +} // namespace Kleo + +#endif // __KLEO_UI_PASSPHRASEDIALOG_H__ diff --git a/certmanager/lib/ui/progressbar.cpp b/certmanager/lib/ui/progressbar.cpp new file mode 100644 index 000000000..96f51fa8a --- /dev/null +++ b/certmanager/lib/ui/progressbar.cpp @@ -0,0 +1,111 @@ +/* + progressbar.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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 "config.h" +#include "progressbar.h" + +#include <qtimer.h> +#include <kdebug.h> + +static const int busyTimerTickInterval = 100; +static const int busyTimerTickIncrement = 5; + +Kleo::ProgressBar::ProgressBar( QWidget * parent, const char * name, WFlags f ) + : QProgressBar( 0, parent, name, f ), + mRealProgress( -1 ) +{ + mBusyTimer = new QTimer( this ); + connect( mBusyTimer, SIGNAL(timeout()), SLOT(slotBusyTimerTick()) ); + fixup( true ); +} + +void Kleo::ProgressBar::slotProgress( const QString &, int cur, int tot ) { + setProgress( cur, tot ); +} + +void Kleo::ProgressBar::slotProgress( const QString &, int, int cur, int tot ) { + setProgress( cur, tot ); +} + +void Kleo::ProgressBar::setTotalSteps( int total ) { + kdDebug() << "Kleo::ProgressBar::setTotalSteps( " << total << " )" << endl; + if ( total == totalSteps() ) + return; + QProgressBar::setTotalSteps( 0 ); + fixup( false ); +} + +void Kleo::ProgressBar::setProgress( int p ) { + kdDebug() << "Kleo::ProgressBar::setProgress( " << p << " )" << endl; + mRealProgress = p; + fixup( true ); +} + +void Kleo::ProgressBar::reset() { + mRealProgress = -1; + fixup( true ); +} + +void Kleo::ProgressBar::slotBusyTimerTick() { + fixup( false ); + if ( mBusyTimer->isActive() ) + QProgressBar::setProgress( QProgressBar::progress() + busyTimerTickIncrement ); +} + +void Kleo::ProgressBar::fixup( bool newValue ) { + const int cur = QProgressBar::progress(); + const int tot = QProgressBar::totalSteps(); + + kdDebug() << "Kleo::ProgressBar::startStopBusyTimer() cur = " << cur << "; tot = " << tot << "; real = " << mRealProgress << endl; + + if ( ( newValue && mRealProgress < 0 ) || ( !newValue && cur < 0 ) ) { + kdDebug() << "(new value) switch to reset" << endl; + mBusyTimer->stop(); + if ( newValue ) + QProgressBar::reset(); + mRealProgress = -1; + } else if ( tot == 0 ) { + kdDebug() << "(new value) switch or stay in busy" << endl; + if ( !mBusyTimer->isActive() ) { + mBusyTimer->start( busyTimerTickInterval ); + if ( newValue ) + QProgressBar::setProgress( mRealProgress ); + } + } else { + kdDebug() << "(new value) normal progress" << endl; + mBusyTimer->stop(); + if ( QProgressBar::progress() != mRealProgress ) + QProgressBar::setProgress( mRealProgress ); + } +} + +#include "progressbar.moc" diff --git a/certmanager/lib/ui/progressbar.h b/certmanager/lib/ui/progressbar.h new file mode 100644 index 000000000..41d96796d --- /dev/null +++ b/certmanager/lib/ui/progressbar.h @@ -0,0 +1,74 @@ +/* + progressbar.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifndef __KLEO_PROGRESSBAR_H__ +#define __KLEO_PROGRESSBAR_H__ + +#include <qprogressbar.h> +#include <kdepimmacros.h> +class QTimer; + +namespace Kleo { + + /** + @short A QProgressBar with self-powered busy indicator + */ + class KDE_EXPORT ProgressBar : public QProgressBar { + Q_OBJECT + public: + ProgressBar( QWidget * parent=0, const char * name=0, WFlags f=0 ); + + public slots: + void slotProgress( const QString & message, int type, int current, int total ); + void slotProgress( const QString & message, int current, int total ); + /*! reimplementation to support self-powered busy indicator */ + void setProgress( int progress ); + /*! reimplementation to support self-powered busy indicator */ + void setTotalSteps( int total ); + /*! reimplementation to support self-powered busy indicator */ + void reset(); + /*! reimplementation to preserve visibility */ + void setProgress( int cur, int tot ) { QProgressBar::setProgress( cur, tot ); } + + private slots: + void slotBusyTimerTick(); + + private: + void fixup( bool ); + + private: + QTimer * mBusyTimer; + int mRealProgress; + }; +} + +#endif // __KLEO_PROGRESSBAR_H__ diff --git a/certmanager/lib/ui/progressdialog.cpp b/certmanager/lib/ui/progressdialog.cpp new file mode 100644 index 000000000..bb66aca17 --- /dev/null +++ b/certmanager/lib/ui/progressdialog.cpp @@ -0,0 +1,98 @@ +/* + progressdialog.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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 "progressdialog.h" + +#include "progressbar.h" + +#include <kleo/job.h> + +#include <kdebug.h> +#include <klocale.h> + +#include <qtimer.h> + +#include <assert.h> + +Kleo::ProgressDialog::ProgressDialog( Job * job, const QString & baseText, + QWidget * creator, const char * name, WFlags f ) + : QProgressDialog( creator, name, false, f ), mBaseText( baseText ) +{ + assert( job ); + setBar( new ProgressBar( this, "replacement progressbar in Kleo::ProgressDialog" ) ); + + setMinimumDuration( 2000 /*ms*/ ); + setAutoReset( false ); + setAutoClose( false ); + setLabelText( baseText ); + setProgress( 0, 0 ); // activate busy indicator + + connect( job, SIGNAL(progress(const QString&,int,int)), + SLOT(slotProgress(const QString&,int,int)) ); + connect( job, SIGNAL(done()), SLOT(slotDone()) ); + connect( this, SIGNAL(canceled()), + job, SLOT(slotCancel()) ); + + QTimer::singleShot( minimumDuration(), this, SLOT(forceShow()) ); +} + +Kleo::ProgressDialog::~ProgressDialog() { + +} + +void Kleo::ProgressDialog::setMinimumDuration( int ms ) { + if ( 0 < ms && ms < minimumDuration() ) + QTimer::singleShot( ms, this, SLOT(forceShow()) ); + QProgressDialog::setMinimumDuration( ms ); +} + +void Kleo::ProgressDialog::slotProgress( const QString & what, int current, int total ) { + kdDebug(5150) << "Kleo::ProgressDialog::slotProgress( \"" << what << "\", " + << current << ", " << total << " )" << endl; + if ( mBaseText.isEmpty() ) + setLabelText( what ); + else if ( what.isEmpty() ) + setLabelText( mBaseText ); + else + setLabelText( i18n( "%1: %2" ).arg( mBaseText, what ) ); + setProgress( current, total ); +} + +void Kleo::ProgressDialog::slotDone() { + kdDebug(5150) << "Kleo::ProgressDialog::slotDone()" << endl; + hide(); + deleteLater(); +} + + +#include "progressdialog.moc" + diff --git a/certmanager/lib/ui/progressdialog.h b/certmanager/lib/ui/progressdialog.h new file mode 100644 index 000000000..0b419aabb --- /dev/null +++ b/certmanager/lib/ui/progressdialog.h @@ -0,0 +1,66 @@ +/* + progressdialog.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifndef __KLEO_PROGRESSDIALOG_H__ +#define __KLEO_PROGRESSDIALOG_H__ + +#include <qprogressdialog.h> +#include <qstring.h> +#include <kdepimmacros.h> +namespace Kleo { + + class Job; + + /** + @short A progress dialog for Kleo::Jobs + */ + class KDE_EXPORT ProgressDialog : public QProgressDialog { + Q_OBJECT + public: + ProgressDialog( Job * job, const QString & baseText, + QWidget * creator=0, const char * name=0, WFlags f=0 ); + ~ProgressDialog(); + + public slots: + /*! reimplementation */ + void setMinimumDuration( int ms ); + + private slots: + void slotProgress( const QString & what, int current, int total ); + void slotDone(); + private: + QString mBaseText; + }; + +} + +#endif // __KLEO_PROGRESSDIALOG_H__ |