diff --git a/kmail/configuredialog.cpp b/kmail/configuredialog.cpp index d26dccbcae..278dd9d1fd 100644 --- a/kmail/configuredialog.cpp +++ b/kmail/configuredialog.cpp @@ -1,5221 +1,5228 @@ /* -*- mode: C++; c-file-style: "gnu" -*- * kmail: KDE mail client * This file: Copyright (C) 2000 Espen Sand, espen@kde.org * Copyright (C) 2001-2003 Marc Mutz, mutz@kde.org * Contains code segments and ideas from earlier kmail dialog code. * * This program 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. * * This program 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. * */ // This must be first #include // my headers: #include "configuredialog.h" #include "configuredialog_p.h" #include "globalsettings.h" #include "replyphrases.h" #include "templatesconfiguration_kfg.h" // other KMail headers: #include "kmkernel.h" #include "simplestringlisteditor.h" #include "accountdialog.h" using KMail::AccountDialog; #include "colorlistbox.h" #include "kmacctseldlg.h" #include "messagesender.h" #include "kmtransport.h" #include "kmfoldermgr.h" #include #include "identitylistview.h" using KMail::IdentityListView; using KMail::IdentityListViewItem; #include "kcursorsaver.h" #include "accountmanager.h" #include #include #include #include "templatesconfiguration.h" #include "customtemplates.h" #include "folderrequester.h" using KMail::FolderRequester; #include "accountcombobox.h" #include "imapaccountbase.h" using KMail::ImapAccountBase; #include "folderstorage.h" #include "kmfolder.h" #include "kmmainwidget.h" #include "recentaddresses.h" using KRecentAddress::RecentAddresses; #include "completionordereditor.h" #include "ldapclient.h" #include "index.h" using KMail::IdentityListView; using KMail::IdentityListViewItem; #include "identitydialog.h" using KMail::IdentityDialog; // other kdenetwork headers: #include #include using KMime::DateFormatter; #include #include #include #include #include // other KDE headers: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt headers: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // other headers: #include #include #ifndef _PATH_SENDMAIL #define _PATH_SENDMAIL "/usr/sbin/sendmail" #endif #ifdef DIM #undef DIM #endif #define DIM(x) sizeof(x) / sizeof(*x) namespace { struct EnumConfigEntryItem { const char * key; // config key value, as appears in config file const char * desc; // description, to be i18n()ized }; struct EnumConfigEntry { const char * group; const char * key; const char * desc; const EnumConfigEntryItem * items; int numItems; int defaultItem; }; struct BoolConfigEntry { const char * group; const char * key; const char * desc; bool defaultValue; }; static const char * lockedDownWarning = I18N_NOOP("

This setting has been fixed by your administrator.

" "

If you think this is an error, please contact him.

"); void checkLockDown( QWidget * w, const KConfigBase & c, const char * key ) { if ( c.entryIsImmutable( key ) ) { w->setEnabled( false ); QToolTip::add( w, i18n( lockedDownWarning ) ); } else { QToolTip::remove( w ); } } void populateButtonGroup( QButtonGroup * g, const EnumConfigEntry & e ) { g->setTitle( i18n( e.desc ) ); g->layout()->setSpacing( KDialog::spacingHint() ); for ( int i = 0 ; i < e.numItems ; ++i ) g->insert( new QRadioButton( i18n( e.items[i].desc ), g ), i ); } void populateCheckBox( QCheckBox * b, const BoolConfigEntry & e ) { b->setText( i18n( e.desc ) ); } void loadWidget( QCheckBox * b, const KConfigBase & c, const BoolConfigEntry & e ) { Q_ASSERT( c.group() == e.group ); checkLockDown( b, c, e.key ); b->setChecked( c.readBoolEntry( e.key, e.defaultValue ) ); } void loadWidget( QButtonGroup * g, const KConfigBase & c, const EnumConfigEntry & e ) { Q_ASSERT( c.group() == e.group ); Q_ASSERT( g->count() == e.numItems ); checkLockDown( g, c, e.key ); const QString s = c.readEntry( e.key, e.items[e.defaultItem].key ); for ( int i = 0 ; i < e.numItems ; ++i ) if ( s == e.items[i].key ) { g->setButton( i ); return; } g->setButton( e.defaultItem ); } void saveCheckBox( QCheckBox * b, KConfigBase & c, const BoolConfigEntry & e ) { Q_ASSERT( c.group() == e.group ); c.writeEntry( e.key, b->isChecked() ); } void saveButtonGroup( QButtonGroup * g, KConfigBase & c, const EnumConfigEntry & e ) { Q_ASSERT( c.group() == e.group ); Q_ASSERT( g->count() == e.numItems ); c.writeEntry( e.key, e.items[ g->id( g->selected() ) ].key ); } template inline void loadProfile( T_Widget * g, const KConfigBase & c, const T_Entry & e ) { if ( c.hasKey( e.key ) ) loadWidget( g, c, e ); } } ConfigureDialog::ConfigureDialog( QWidget *parent, const char *name, bool modal ) : KCMultiDialog( KDialogBase::IconList, KGuiItem( i18n( "&Load Profile..." ) ), KGuiItem(), User2, i18n( "Configure" ), parent, name, modal ) , mProfileDialog( 0 ) { KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() ); showButton( User1, true ); addModule ( "kmail_config_identity", false ); addModule ( "kmail_config_accounts", false ); addModule ( "kmail_config_appearance", false ); addModule ( "kmail_config_composer", false ); addModule ( "kmail_config_security", false ); addModule ( "kmail_config_misc", false ); // We store the size of the dialog on hide, because otherwise // the KCMultiDialog starts with the size of the first kcm, not // the largest one. This way at least after the first showing of // the largest kcm the size is kept. KConfigGroup geometry( KMKernel::config(), "Geometry" ); int width = geometry.readNumEntry( "ConfigureDialogWidth" ); int height = geometry.readNumEntry( "ConfigureDialogHeight" ); if ( width != 0 && height != 0 ) { setMinimumSize( width, height ); } } void ConfigureDialog::hideEvent( QHideEvent *ev ) { KConfigGroup geometry( KMKernel::config(), "Geometry" ); geometry.writeEntry( "ConfigureDialogWidth", width() ); geometry.writeEntry( "ConfigureDialogHeight",height() ); KDialogBase::hideEvent( ev ); } ConfigureDialog::~ConfigureDialog() { } void ConfigureDialog::slotApply() { KCMultiDialog::slotApply(); GlobalSettings::self()->writeConfig(); emit configChanged(); } void ConfigureDialog::slotOk() { KCMultiDialog::slotOk(); GlobalSettings::self()->writeConfig(); emit configChanged(); } void ConfigureDialog::slotUser2() { if ( mProfileDialog ) { mProfileDialog->raise(); return; } mProfileDialog = new ProfileDialog( this, "mProfileDialog" ); connect( mProfileDialog, SIGNAL(profileSelected(KConfig*)), this, SIGNAL(installProfile(KConfig*)) ); mProfileDialog->show(); } // ************************************************************* // * * // * IdentityPage * // * * // ************************************************************* QString IdentityPage::helpAnchor() const { return QString::fromLatin1("configure-identity"); } IdentityPage::IdentityPage( QWidget * parent, const char * name ) : ConfigModule( parent, name ), mIdentityDialog( 0 ) { QHBoxLayout * hlay = new QHBoxLayout( this, 0, KDialog::spacingHint() ); mIdentityList = new IdentityListView( this ); connect( mIdentityList, SIGNAL(selectionChanged()), SLOT(slotIdentitySelectionChanged()) ); connect( mIdentityList, SIGNAL(itemRenamed(QListViewItem*,const QString&,int)), SLOT(slotRenameIdentity(QListViewItem*,const QString&,int)) ); connect( mIdentityList, SIGNAL(doubleClicked(QListViewItem*,const QPoint&,int)), SLOT(slotModifyIdentity()) ); connect( mIdentityList, SIGNAL(contextMenu(KListView*,QListViewItem*,const QPoint&)), SLOT(slotContextMenu(KListView*,QListViewItem*,const QPoint&)) ); // ### connect dragged(...), ... hlay->addWidget( mIdentityList, 1 ); QVBoxLayout * vlay = new QVBoxLayout( hlay ); // inherits spacing QPushButton * button = new QPushButton( i18n("&Add..."), this ); mModifyButton = new QPushButton( i18n("&Modify..."), this ); mRenameButton = new QPushButton( i18n("&Rename"), this ); mRemoveButton = new QPushButton( i18n("Remo&ve"), this ); mSetAsDefaultButton = new QPushButton( i18n("Set as &Default"), this ); button->setAutoDefault( false ); mModifyButton->setAutoDefault( false ); mModifyButton->setEnabled( false ); mRenameButton->setAutoDefault( false ); mRenameButton->setEnabled( false ); mRemoveButton->setAutoDefault( false ); mRemoveButton->setEnabled( false ); mSetAsDefaultButton->setAutoDefault( false ); mSetAsDefaultButton->setEnabled( false ); connect( button, SIGNAL(clicked()), this, SLOT(slotNewIdentity()) ); connect( mModifyButton, SIGNAL(clicked()), this, SLOT(slotModifyIdentity()) ); connect( mRenameButton, SIGNAL(clicked()), this, SLOT(slotRenameIdentity()) ); connect( mRemoveButton, SIGNAL(clicked()), this, SLOT(slotRemoveIdentity()) ); connect( mSetAsDefaultButton, SIGNAL(clicked()), this, SLOT(slotSetAsDefault()) ); vlay->addWidget( button ); vlay->addWidget( mModifyButton ); vlay->addWidget( mRenameButton ); vlay->addWidget( mRemoveButton ); vlay->addWidget( mSetAsDefaultButton ); vlay->addStretch( 1 ); load(); } void IdentityPage::load() { KPIM::IdentityManager * im = kmkernel->identityManager(); mOldNumberOfIdentities = im->shadowIdentities().count(); // Fill the list: mIdentityList->clear(); QListViewItem * item = 0; for ( KPIM::IdentityManager::Iterator it = im->modifyBegin() ; it != im->modifyEnd() ; ++it ) item = new IdentityListViewItem( mIdentityList, item, *it ); mIdentityList->setSelected( mIdentityList->currentItem(), true ); } void IdentityPage::save() { assert( !mIdentityDialog ); kmkernel->identityManager()->sort(); kmkernel->identityManager()->commit(); if( mOldNumberOfIdentities < 2 && mIdentityList->childCount() > 1 ) { // have more than one identity, so better show the combo in the // composer now: KConfigGroup composer( KMKernel::config(), "Composer" ); int showHeaders = composer.readNumEntry( "headers", HDR_STANDARD ); showHeaders |= HDR_IDENTITY; composer.writeEntry( "headers", showHeaders ); } // and now the reverse if( mOldNumberOfIdentities > 1 && mIdentityList->childCount() < 2 ) { // have only one identity, so remove the combo in the composer: KConfigGroup composer( KMKernel::config(), "Composer" ); int showHeaders = composer.readNumEntry( "headers", HDR_STANDARD ); showHeaders &= ~HDR_IDENTITY; composer.writeEntry( "headers", showHeaders ); } } void IdentityPage::slotNewIdentity() { assert( !mIdentityDialog ); KPIM::IdentityManager * im = kmkernel->identityManager(); NewIdentityDialog dialog( im->shadowIdentities(), this, "new", true ); if( dialog.exec() == QDialog::Accepted ) { QString identityName = dialog.identityName().stripWhiteSpace(); assert( !identityName.isEmpty() ); // // Construct a new Identity: // switch ( dialog.duplicateMode() ) { case NewIdentityDialog::ExistingEntry: { KPIM::Identity & dupThis = im->modifyIdentityForName( dialog.duplicateIdentity() ); im->newFromExisting( dupThis, identityName ); break; } case NewIdentityDialog::ControlCenter: im->newFromControlCenter( identityName ); break; case NewIdentityDialog::Empty: im->newFromScratch( identityName ); default: ; } // // Insert into listview: // KPIM::Identity & newIdent = im->modifyIdentityForName( identityName ); QListViewItem * item = mIdentityList->selectedItem(); if ( item ) item = item->itemAbove(); mIdentityList->setSelected( new IdentityListViewItem( mIdentityList, /*after*/ item, newIdent ), true ); slotModifyIdentity(); } } void IdentityPage::slotModifyIdentity() { assert( !mIdentityDialog ); IdentityListViewItem * item = dynamic_cast( mIdentityList->selectedItem() ); if ( !item ) return; mIdentityDialog = new IdentityDialog( this ); mIdentityDialog->setIdentity( item->identity() ); // Hmm, an unmodal dialog would be nicer, but a modal one is easier ;-) if ( mIdentityDialog->exec() == QDialog::Accepted ) { mIdentityDialog->updateIdentity( item->identity() ); item->redisplay(); emit changed(true); } delete mIdentityDialog; mIdentityDialog = 0; } void IdentityPage::slotRemoveIdentity() { assert( !mIdentityDialog ); KPIM::IdentityManager * im = kmkernel->identityManager(); kdFatal( im->shadowIdentities().count() < 2 ) << "Attempted to remove the last identity!" << endl; IdentityListViewItem * item = dynamic_cast( mIdentityList->selectedItem() ); if ( !item ) return; QString msg = i18n("Do you really want to remove the identity named " "%1?").arg( item->identity().identityName() ); if( KMessageBox::warningContinueCancel( this, msg, i18n("Remove Identity"), KGuiItem(i18n("&Remove"),"editdelete") ) == KMessageBox::Continue ) if ( im->removeIdentity( item->identity().identityName() ) ) { delete item; mIdentityList->setSelected( mIdentityList->currentItem(), true ); refreshList(); } } void IdentityPage::slotRenameIdentity() { assert( !mIdentityDialog ); QListViewItem * item = mIdentityList->selectedItem(); if ( !item ) return; mIdentityList->rename( item, 0 ); } void IdentityPage::slotRenameIdentity( QListViewItem * i, const QString & s, int col ) { assert( col == 0 ); Q_UNUSED( col ); IdentityListViewItem * item = dynamic_cast( i ); if ( !item ) return; QString newName = s.stripWhiteSpace(); if ( !newName.isEmpty() && !kmkernel->identityManager()->shadowIdentities().contains( newName ) ) { KPIM::Identity & ident = item->identity(); ident.setIdentityName( newName ); emit changed(true); } item->redisplay(); } void IdentityPage::slotContextMenu( KListView *, QListViewItem * i, const QPoint & pos ) { IdentityListViewItem * item = dynamic_cast( i ); QPopupMenu * menu = new QPopupMenu( this ); menu->insertItem( i18n("Add..."), this, SLOT(slotNewIdentity()) ); if ( item ) { menu->insertItem( i18n("Modify..."), this, SLOT(slotModifyIdentity()) ); if ( mIdentityList->childCount() > 1 ) menu->insertItem( i18n("Remove"), this, SLOT(slotRemoveIdentity()) ); if ( !item->identity().isDefault() ) menu->insertItem( i18n("Set as Default"), this, SLOT(slotSetAsDefault()) ); } menu->exec( pos ); delete menu; } void IdentityPage::slotSetAsDefault() { assert( !mIdentityDialog ); IdentityListViewItem * item = dynamic_cast( mIdentityList->selectedItem() ); if ( !item ) return; KPIM::IdentityManager * im = kmkernel->identityManager(); im->setAsDefault( item->identity().identityName() ); refreshList(); } void IdentityPage::refreshList() { for ( QListViewItemIterator it( mIdentityList ) ; it.current() ; ++it ) { IdentityListViewItem * item = dynamic_cast(it.current()); if ( item ) item->redisplay(); } emit changed(true); } void IdentityPage::slotIdentitySelectionChanged() { IdentityListViewItem *item = dynamic_cast( mIdentityList->selectedItem() ); mRemoveButton->setEnabled( item && mIdentityList->childCount() > 1 ); mModifyButton->setEnabled( item ); mRenameButton->setEnabled( item ); mSetAsDefaultButton->setEnabled( item && !item->identity().isDefault() ); } void IdentityPage::slotUpdateTransportCombo( const QStringList & sl ) { if ( mIdentityDialog ) mIdentityDialog->slotUpdateTransportCombo( sl ); } // ************************************************************* // * * // * AccountsPage * // * * // ************************************************************* QString AccountsPage::helpAnchor() const { return QString::fromLatin1("configure-accounts"); } AccountsPage::AccountsPage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { // // "Receiving" tab: // mReceivingTab = new ReceivingTab(); addTab( mReceivingTab, i18n( "&Receiving" ) ); connect( mReceivingTab, SIGNAL(accountListChanged(const QStringList &)), this, SIGNAL(accountListChanged(const QStringList &)) ); // // "Sending" tab: // mSendingTab = new SendingTab(); addTab( mSendingTab, i18n( "&Sending" ) ); connect( mSendingTab, SIGNAL(transportListChanged(const QStringList&)), this, SIGNAL(transportListChanged(const QStringList&)) ); load(); } QString AccountsPage::SendingTab::helpAnchor() const { return QString::fromLatin1("configure-accounts-sending"); } AccountsPageSendingTab::AccountsPageSendingTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { mTransportInfoList.setAutoDelete( true ); // temp. vars: QVBoxLayout *vlay; QVBoxLayout *btn_vlay; QHBoxLayout *hlay; QGridLayout *glay; QPushButton *button; QGroupBox *group; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // label: zero stretch ### FIXME more vlay->addWidget( new QLabel( i18n("Outgoing accounts (add at least one):"), this ) ); // hbox layout: stretch 10, spacing inherited from vlay hlay = new QHBoxLayout(); vlay->addLayout( hlay, 10 ); // high stretch b/c of the groupbox's sizeHint // transport list: left widget in hlay; stretch 1 // ### FIXME: allow inline renaming of the account: mTransportList = new ListView( this, "transportList", 5 ); mTransportList->addColumn( i18n("Name") ); mTransportList->addColumn( i18n("Type") ); mTransportList->setAllColumnsShowFocus( true ); mTransportList->setSorting( -1 ); connect( mTransportList, SIGNAL(selectionChanged()), this, SLOT(slotTransportSelected()) ); connect( mTransportList, SIGNAL(doubleClicked( QListViewItem *)), this, SLOT(slotModifySelectedTransport()) ); hlay->addWidget( mTransportList, 1 ); // a vbox layout for the buttons: zero stretch, spacing inherited from hlay btn_vlay = new QVBoxLayout( hlay ); // "add..." button: stretch 0 button = new QPushButton( i18n("A&dd..."), this ); button->setAutoDefault( false ); connect( button, SIGNAL(clicked()), this, SLOT(slotAddTransport()) ); btn_vlay->addWidget( button ); // "modify..." button: stretch 0 mModifyTransportButton = new QPushButton( i18n("&Modify..."), this ); mModifyTransportButton->setAutoDefault( false ); mModifyTransportButton->setEnabled( false ); // b/c no item is selected yet connect( mModifyTransportButton, SIGNAL(clicked()), this, SLOT(slotModifySelectedTransport()) ); btn_vlay->addWidget( mModifyTransportButton ); // "remove" button: stretch 0 mRemoveTransportButton = new QPushButton( i18n("R&emove"), this ); mRemoveTransportButton->setAutoDefault( false ); mRemoveTransportButton->setEnabled( false ); // b/c no item is selected yet connect( mRemoveTransportButton, SIGNAL(clicked()), this, SLOT(slotRemoveSelectedTransport()) ); btn_vlay->addWidget( mRemoveTransportButton ); mSetDefaultTransportButton = new QPushButton( i18n("Set Default"), this ); mSetDefaultTransportButton->setAutoDefault( false ); mSetDefaultTransportButton->setEnabled( false ); connect ( mSetDefaultTransportButton, SIGNAL(clicked()), this, SLOT(slotSetDefaultTransport()) ); btn_vlay->addWidget( mSetDefaultTransportButton ); btn_vlay->addStretch( 1 ); // spacer // "Common options" groupbox: group = new QGroupBox( 0, Qt::Vertical, i18n("Common Options"), this ); vlay->addWidget(group); // a grid layout for the contents of the "common options" group box glay = new QGridLayout( group->layout(), 5, 3, KDialog::spacingHint() ); glay->setColStretch( 2, 10 ); // "confirm before send" check box: mConfirmSendCheck = new QCheckBox( i18n("Confirm &before send"), group ); glay->addMultiCellWidget( mConfirmSendCheck, 0, 0, 0, 1 ); connect( mConfirmSendCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "send on check" combo: mSendOnCheckCombo = new QComboBox( false, group ); mSendOnCheckCombo->insertStringList( QStringList() << i18n("Never Automatically") << i18n("On Manual Mail Checks") << i18n("On All Mail Checks") ); glay->addWidget( mSendOnCheckCombo, 1, 1 ); connect( mSendOnCheckCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "default send method" combo: mSendMethodCombo = new QComboBox( false, group ); mSendMethodCombo->insertStringList( QStringList() << i18n("Send Now") << i18n("Send Later") ); glay->addWidget( mSendMethodCombo, 2, 1 ); connect( mSendMethodCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "message property" combo: // ### FIXME: remove completely? mMessagePropertyCombo = new QComboBox( false, group ); mMessagePropertyCombo->insertStringList( QStringList() << i18n("Allow 8-bit") << i18n("MIME Compliant (Quoted Printable)") ); glay->addWidget( mMessagePropertyCombo, 3, 1 ); connect( mMessagePropertyCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "default domain" input field: mDefaultDomainEdit = new KLineEdit( group ); glay->addMultiCellWidget( mDefaultDomainEdit, 4, 4, 1, 2 ); connect( mDefaultDomainEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); // labels: QLabel *l = new QLabel( mSendOnCheckCombo, /*buddy*/ i18n("Send &messages in outbox folder:"), group ); glay->addWidget( l, 1, 0 ); QString msg = i18n( GlobalSettings::self()->sendOnCheckItem()->whatsThis().utf8() ); QWhatsThis::add( l, msg ); QWhatsThis::add( mSendOnCheckCombo, msg ); glay->addWidget( new QLabel( mSendMethodCombo, /*buddy*/ i18n("Defa&ult send method:"), group ), 2, 0 ); glay->addWidget( new QLabel( mMessagePropertyCombo, /*buddy*/ i18n("Message &property:"), group ), 3, 0 ); l = new QLabel( mDefaultDomainEdit, /*buddy*/ i18n("Defaul&t domain:"), group ); glay->addWidget( l, 4, 0 ); // and now: add QWhatsThis: msg = i18n( "

The default domain is used to complete email " "addresses that only consist of the user's name." "

" ); QWhatsThis::add( l, msg ); QWhatsThis::add( mDefaultDomainEdit, msg ); } void AccountsPage::SendingTab::slotTransportSelected() { QListViewItem *cur = mTransportList->selectedItem(); mModifyTransportButton->setEnabled( cur ); mRemoveTransportButton->setEnabled( cur ); mSetDefaultTransportButton->setEnabled( cur ); } // adds a number to @p name to make the name unique static inline QString uniqueName( const QStringList & list, const QString & name ) { int suffix = 1; QString result = name; while ( list.find( result ) != list.end() ) { result = i18n("%1: name; %2: number appended to it to make it unique " "among a list of names", "%1 %2") .arg( name ).arg( suffix ); suffix++; } return result; } void AccountsPage::SendingTab::slotSetDefaultTransport() { QListViewItem *item = mTransportList->selectedItem(); if ( !item ) return; KMTransportInfo ti; QListViewItemIterator it( mTransportList ); for ( ; it.current(); ++it ) { ti.readConfig( KMTransportInfo::findTransport( it.current()->text(0) )); if ( ti.type != "sendmail" ) { it.current()->setText( 1, "smtp" ); } else { it.current()->setText( 1, "sendmail" ); } } if ( item->text(1) != "sendmail" ) { item->setText( 1, i18n( "smtp (Default)" )); } else { item->setText( 1, i18n( "sendmail (Default)" )); } GlobalSettings::self()->setDefaultTransport( item->text(0) ); } void AccountsPage::SendingTab::slotAddTransport() { int transportType; { // limit scope of selDialog KMTransportSelDlg selDialog( this ); if ( selDialog.exec() != QDialog::Accepted ) return; transportType = selDialog.selected(); } KMTransportInfo *transportInfo = new KMTransportInfo(); switch ( transportType ) { case 0: // smtp transportInfo->type = QString::fromLatin1("smtp"); break; case 1: // sendmail transportInfo->type = QString::fromLatin1("sendmail"); transportInfo->name = i18n("Sendmail"); transportInfo->host = _PATH_SENDMAIL; // ### FIXME: use const, not #define break; default: assert( 0 ); } KMTransportDialog dialog( i18n("Add Transport"), transportInfo, this ); // create list of names: // ### move behind dialog.exec()? QStringList transportNames; QPtrListIterator it( mTransportInfoList ); for ( it.toFirst() ; it.current() ; ++it ) transportNames << (*it)->name; if( dialog.exec() != QDialog::Accepted ) { delete transportInfo; return; } // disambiguate the name by appending a number: // ### FIXME: don't allow this error to happen in the first place! transportInfo->name = uniqueName( transportNames, transportInfo->name ); // append to names and transportinfo lists: transportNames << transportInfo->name; mTransportInfoList.append( transportInfo ); // append to listview: // ### FIXME: insert before the selected item, append on empty selection QListViewItem *lastItem = mTransportList->firstChild(); QString typeDisplayName; if ( lastItem ) { typeDisplayName = transportInfo->type; } else { typeDisplayName = i18n("%1: type of transport. Result used in " "Configure->Accounts->Sending listview, \"type\" " "column, first row, to indicate that this is the " "default transport", "%1 (Default)") .arg( transportInfo->type ); GlobalSettings::self()->setDefaultTransport( transportInfo->name ); } (void) new QListViewItem( mTransportList, lastItem, transportInfo->name, typeDisplayName ); // notify anyone who cares: emit transportListChanged( transportNames ); emit changed( true ); } void AccountsPage::SendingTab::slotModifySelectedTransport() { QListViewItem *item = mTransportList->selectedItem(); if ( !item ) return; const QString& originalTransport = item->text(0); QPtrListIterator it( mTransportInfoList ); for ( it.toFirst() ; it.current() ; ++it ) if ( (*it)->name == item->text(0) ) break; if ( !it.current() ) return; KMTransportDialog dialog( i18n("Modify Transport"), (*it), this ); if ( dialog.exec() != QDialog::Accepted ) return; // create the list of names of transports, but leave out the current // item: QStringList transportNames; QPtrListIterator jt( mTransportInfoList ); int entryLocation = -1; for ( jt.toFirst() ; jt.current() ; ++jt ) if ( jt != it ) transportNames << (*jt)->name; else entryLocation = transportNames.count(); assert( entryLocation >= 0 ); // make the new name unique by appending a high enough number: (*it)->name = uniqueName( transportNames, (*it)->name ); // change the list item to the new name item->setText( 0, (*it)->name ); // and insert the new name at the position of the old in the list of // strings; then broadcast the new list: transportNames.insert( transportNames.at( entryLocation ), (*it)->name ); const QString& newTransportName = (*it)->name; QStringList changedIdents; KPIM::IdentityManager * im = kmkernel->identityManager(); for ( KPIM::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) { if ( originalTransport == (*it).transport() ) { (*it).setTransport( newTransportName ); changedIdents += (*it).identityName(); } } if ( !changedIdents.isEmpty() ) { QString information = i18n( "This identity has been changed to use the modified transport:", "These %n identities have been changed to use the modified transport:", changedIdents.count() ); KMessageBox::informationList( this, information, changedIdents ); } emit transportListChanged( transportNames ); emit changed( true ); } void AccountsPage::SendingTab::slotRemoveSelectedTransport() { QListViewItem *item = mTransportList->selectedItem(); if ( !item ) return; bool selectedTransportWasDefault = false; if ( item->text( 0 ) == GlobalSettings::self()->defaultTransport() ) { selectedTransportWasDefault = true; } QStringList changedIdents; KPIM::IdentityManager * im = kmkernel->identityManager(); for ( KPIM::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) { if ( item->text( 0 ) == (*it).transport() ) { (*it).setTransport( QString::null ); changedIdents += (*it).identityName(); } } // if the deleted transport is the currently used transport reset it to default const QString& currentTransport = GlobalSettings::self()->currentTransport(); if ( item->text( 0 ) == currentTransport ) { GlobalSettings::self()->setCurrentTransport( QString::null ); } if ( !changedIdents.isEmpty() ) { QString information = i18n( "This identity has been changed to use the default transport:", "These %n identities have been changed to use the default transport:", changedIdents.count() ); KMessageBox::informationList( this, information, changedIdents ); } QPtrListIterator it( mTransportInfoList ); for ( it.toFirst() ; it.current() ; ++it ) if ( (*it)->name == item->text(0) ) break; if ( !it.current() ) return; KMTransportInfo ti; if( selectedTransportWasDefault ) { QListViewItem *newCurrent = item->itemBelow(); if ( !newCurrent ) newCurrent = item->itemAbove(); //mTransportList->removeItem( item ); if ( newCurrent ) { mTransportList->setCurrentItem( newCurrent ); mTransportList->setSelected( newCurrent, true ); GlobalSettings::self()->setDefaultTransport( newCurrent->text(0) ); ti.readConfig( KMTransportInfo::findTransport( newCurrent->text(0) )); if ( ti.type != "sendmail" ) { newCurrent->setText( 1, i18n("smtp (Default)") ); } else { newCurrent->setText( 1, i18n("sendmail (Default)" )); } } else { GlobalSettings::self()->setDefaultTransport( QString::null ); } } delete item; mTransportInfoList.remove( it ); QStringList transportNames; for ( it.toFirst() ; it.current() ; ++it ) transportNames << (*it)->name; emit transportListChanged( transportNames ); emit changed( true ); } void AccountsPage::SendingTab::doLoadFromGlobalSettings() { mSendOnCheckCombo->setCurrentItem( GlobalSettings::self()->sendOnCheck() ); } void AccountsPage::SendingTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General"); KConfigGroup composer( KMKernel::config(), "Composer"); int numTransports = general.readNumEntry("transports", 0); QListViewItem *top = 0; mTransportInfoList.clear(); mTransportList->clear(); QStringList transportNames; for ( int i = 1 ; i <= numTransports ; i++ ) { KMTransportInfo *ti = new KMTransportInfo(); ti->readConfig(i); mTransportInfoList.append( ti ); transportNames << ti->name; top = new QListViewItem( mTransportList, top, ti->name, ti->type ); } emit transportListChanged( transportNames ); const QString &defaultTransport = GlobalSettings::self()->defaultTransport(); QListViewItemIterator it( mTransportList ); for ( ; it.current(); ++it ) { if ( it.current()->text(0) == defaultTransport ) { if ( it.current()->text(1) != "sendmail" ) { it.current()->setText( 1, i18n( "smtp (Default)" )); } else { it.current()->setText( 1, i18n( "sendmail (Default)" )); } } else { if ( it.current()->text(1) != "sendmail" ) { it.current()->setText( 1, "smtp" ); } else { it.current()->setText( 1, "sendmail" ); } } } mSendMethodCombo->setCurrentItem( kmkernel->msgSender()->sendImmediate() ? 0 : 1 ); mMessagePropertyCombo->setCurrentItem( kmkernel->msgSender()->sendQuotedPrintable() ? 1 : 0 ); mConfirmSendCheck->setChecked( composer.readBoolEntry( "confirm-before-send", false ) ); QString str = general.readEntry( "Default domain" ); if( str.isEmpty() ) { //### FIXME: Use the global convenience function instead of the homebrewed // solution once we can rely on HEAD kdelibs. //str = KGlobal::hostname(); ??????? char buffer[256]; if ( !gethostname( buffer, 255 ) ) // buffer need not be NUL-terminated if it has full length buffer[255] = 0; else buffer[0] = 0; str = QString::fromLatin1( *buffer ? buffer : "localhost" ); } mDefaultDomainEdit->setText( str ); } void AccountsPage::SendingTab::save() { KConfigGroup general( KMKernel::config(), "General" ); KConfigGroup composer( KMKernel::config(), "Composer" ); // Save transports: general.writeEntry( "transports", mTransportInfoList.count() ); QPtrListIterator it( mTransportInfoList ); for ( int i = 1 ; it.current() ; ++it, ++i ) (*it)->writeConfig(i); // Save common options: GlobalSettings::self()->setSendOnCheck( mSendOnCheckCombo->currentItem() ); kmkernel->msgSender()->setSendImmediate( mSendMethodCombo->currentItem() == 0 ); kmkernel->msgSender()->setSendQuotedPrintable( mMessagePropertyCombo->currentItem() == 1 ); kmkernel->msgSender()->writeConfig( false ); // don't sync composer.writeEntry("confirm-before-send", mConfirmSendCheck->isChecked() ); general.writeEntry( "Default domain", mDefaultDomainEdit->text() ); } QString AccountsPage::ReceivingTab::helpAnchor() const { return QString::fromLatin1("configure-accounts-receiving"); } AccountsPageReceivingTab::AccountsPageReceivingTab( QWidget * parent, const char * name ) : ConfigModuleTab ( parent, name ) { // temp. vars: QVBoxLayout *vlay; QVBoxLayout *btn_vlay; QHBoxLayout *hlay; QPushButton *button; QGroupBox *group; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // label: zero stretch vlay->addWidget( new QLabel( i18n("Incoming accounts (add at least one):"), this ) ); // hbox layout: stretch 10, spacing inherited from vlay hlay = new QHBoxLayout(); vlay->addLayout( hlay, 10 ); // high stretch to suppress groupbox's growing // account list: left widget in hlay; stretch 1 mAccountList = new ListView( this, "accountList", 5 ); mAccountList->addColumn( i18n("Name") ); mAccountList->addColumn( i18n("Type") ); mAccountList->addColumn( i18n("Folder") ); mAccountList->setAllColumnsShowFocus( true ); mAccountList->setSorting( -1 ); connect( mAccountList, SIGNAL(selectionChanged()), this, SLOT(slotAccountSelected()) ); connect( mAccountList, SIGNAL(doubleClicked( QListViewItem *)), this, SLOT(slotModifySelectedAccount()) ); hlay->addWidget( mAccountList, 1 ); // a vbox layout for the buttons: zero stretch, spacing inherited from hlay btn_vlay = new QVBoxLayout( hlay ); // "add..." button: stretch 0 button = new QPushButton( i18n("A&dd..."), this ); button->setAutoDefault( false ); connect( button, SIGNAL(clicked()), this, SLOT(slotAddAccount()) ); btn_vlay->addWidget( button ); // "modify..." button: stretch 0 mModifyAccountButton = new QPushButton( i18n("&Modify..."), this ); mModifyAccountButton->setAutoDefault( false ); mModifyAccountButton->setEnabled( false ); // b/c no item is selected yet connect( mModifyAccountButton, SIGNAL(clicked()), this, SLOT(slotModifySelectedAccount()) ); btn_vlay->addWidget( mModifyAccountButton ); // "remove..." button: stretch 0 mRemoveAccountButton = new QPushButton( i18n("R&emove"), this ); mRemoveAccountButton->setAutoDefault( false ); mRemoveAccountButton->setEnabled( false ); // b/c no item is selected yet connect( mRemoveAccountButton, SIGNAL(clicked()), this, SLOT(slotRemoveSelectedAccount()) ); btn_vlay->addWidget( mRemoveAccountButton ); btn_vlay->addStretch( 1 ); // spacer mCheckmailStartupCheck = new QCheckBox( i18n("Chec&k mail on startup"), this ); vlay->addWidget( mCheckmailStartupCheck ); connect( mCheckmailStartupCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "New Mail Notification" group box: stretch 0 group = new QVGroupBox( i18n("New Mail Notification"), this ); vlay->addWidget( group ); group->layout()->setSpacing( KDialog::spacingHint() ); // "beep on new mail" check box: mBeepNewMailCheck = new QCheckBox(i18n("&Beep"), group ); mBeepNewMailCheck->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ) ); connect( mBeepNewMailCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "Detailed new mail notification" check box mVerboseNotificationCheck = new QCheckBox( i18n( "Deta&iled new mail notification" ), group ); mVerboseNotificationCheck->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ) ); QToolTip::add( mVerboseNotificationCheck, i18n( "Show for each folder the number of newly arrived " "messages" ) ); QWhatsThis::add( mVerboseNotificationCheck, GlobalSettings::self()->verboseNewMailNotificationItem()->whatsThis() ); connect( mVerboseNotificationCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "Other Actions" button: mOtherNewMailActionsButton = new QPushButton( i18n("Other Actio&ns"), group ); mOtherNewMailActionsButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); connect( mOtherNewMailActionsButton, SIGNAL(clicked()), this, SLOT(slotEditNotifications()) ); } AccountsPageReceivingTab::~AccountsPageReceivingTab() { // When hitting Cancel or closing the dialog with the window-manager-button, // we have a number of things to clean up: // The newly created accounts QValueList< QGuardedPtr >::Iterator it; for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) { delete (*it); } mNewAccounts.clear(); // The modified accounts QValueList::Iterator j; for ( j = mModifiedAccounts.begin() ; j != mModifiedAccounts.end() ; ++j ) { delete (*j)->newAccount; delete (*j); } mModifiedAccounts.clear(); } void AccountsPage::ReceivingTab::slotAccountSelected() { QListViewItem * item = mAccountList->selectedItem(); mModifyAccountButton->setEnabled( item ); mRemoveAccountButton->setEnabled( item ); } QStringList AccountsPage::ReceivingTab::occupiedNames() { QStringList accountNames = kmkernel->acctMgr()->getAccounts(); QValueList::Iterator k; for (k = mModifiedAccounts.begin(); k != mModifiedAccounts.end(); ++k ) if ((*k)->oldAccount) accountNames.remove( (*k)->oldAccount->name() ); QValueList< QGuardedPtr >::Iterator l; for (l = mAccountsToDelete.begin(); l != mAccountsToDelete.end(); ++l ) if (*l) accountNames.remove( (*l)->name() ); QValueList< QGuardedPtr >::Iterator it; for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) if (*it) accountNames += (*it)->name(); QValueList::Iterator j; for (j = mModifiedAccounts.begin(); j != mModifiedAccounts.end(); ++j ) accountNames += (*j)->newAccount->name(); return accountNames; } void AccountsPage::ReceivingTab::slotAddAccount() { KMAcctSelDlg accountSelectorDialog( this ); if( accountSelectorDialog.exec() != QDialog::Accepted ) return; const char *accountType = 0; switch ( accountSelectorDialog.selected() ) { case 0: accountType = "local"; break; case 1: accountType = "pop"; break; case 2: accountType = "imap"; break; case 3: accountType = "cachedimap"; break; case 4: accountType = "maildir"; break; default: // ### FIXME: How should this happen??? // replace with assert. KMessageBox::sorry( this, i18n("Unknown account type selected") ); return; } KMAccount *account = kmkernel->acctMgr()->create( QString::fromLatin1( accountType ) ); if ( !account ) { // ### FIXME: Give the user more information. Is this error // recoverable? KMessageBox::sorry( this, i18n("Unable to create account") ); return; } account->init(); // fill the account fields with good default values AccountDialog dialog( i18n("Add Account"), account, this ); QStringList accountNames = occupiedNames(); if( dialog.exec() != QDialog::Accepted ) { delete account; return; } account->deinstallTimer(); account->setName( uniqueName( accountNames, account->name() ) ); QListViewItem *after = mAccountList->firstChild(); while ( after && after->nextSibling() ) after = after->nextSibling(); QListViewItem *listItem = new QListViewItem( mAccountList, after, account->name(), account->type() ); if( account->folder() ) listItem->setText( 2, account->folder()->label() ); mNewAccounts.append( account ); emit changed( true ); } void AccountsPage::ReceivingTab::slotModifySelectedAccount() { QListViewItem *listItem = mAccountList->selectedItem(); if( !listItem ) return; KMAccount *account = 0; QValueList::Iterator j; for (j = mModifiedAccounts.begin(); j != mModifiedAccounts.end(); ++j ) if ( (*j)->newAccount->name() == listItem->text(0) ) { account = (*j)->newAccount; break; } if ( !account ) { QValueList< QGuardedPtr >::Iterator it; for ( it = mNewAccounts.begin() ; it != mNewAccounts.end() ; ++it ) if ( (*it)->name() == listItem->text(0) ) { account = *it; break; } if ( !account ) { account = kmkernel->acctMgr()->findByName( listItem->text(0) ); if( !account ) { // ### FIXME: How should this happen? See above. KMessageBox::sorry( this, i18n("Unable to locate account") ); return; } if ( account->type() == "imap" || account->type() == "cachedimap" ) { ImapAccountBase* ai = static_cast( account ); if ( ai->namespaces().isEmpty() || ai->namespaceToDelimiter().isEmpty() ) { // connect to server - the namespaces are fetched automatically kdDebug(5006) << "slotModifySelectedAccount - connect" << endl; ai->makeConnection(); } } ModifiedAccountsType *mod = new ModifiedAccountsType; mod->oldAccount = account; mod->newAccount = kmkernel->acctMgr()->create( account->type(), account->name() ); mod->newAccount->pseudoAssign( account ); mModifiedAccounts.append( mod ); account = mod->newAccount; } } QStringList accountNames = occupiedNames(); accountNames.remove( account->name() ); AccountDialog dialog( i18n("Modify Account"), account, this ); if( dialog.exec() != QDialog::Accepted ) return; account->setName( uniqueName( accountNames, account->name() ) ); listItem->setText( 0, account->name() ); listItem->setText( 1, account->type() ); if( account->folder() ) listItem->setText( 2, account->folder()->label() ); emit changed( true ); } void AccountsPage::ReceivingTab::slotRemoveSelectedAccount() { QListViewItem *listItem = mAccountList->selectedItem(); if( !listItem ) return; KMAccount *acct = 0; QValueList::Iterator j; for ( j = mModifiedAccounts.begin() ; j != mModifiedAccounts.end() ; ++j ) if ( (*j)->newAccount->name() == listItem->text(0) ) { acct = (*j)->oldAccount; mAccountsToDelete.append( acct ); mModifiedAccounts.remove( j ); break; } if ( !acct ) { QValueList< QGuardedPtr >::Iterator it; for ( it = mNewAccounts.begin() ; it != mNewAccounts.end() ; ++it ) if ( (*it)->name() == listItem->text(0) ) { acct = *it; mNewAccounts.remove( it ); break; } } if ( !acct ) { acct = kmkernel->acctMgr()->findByName( listItem->text(0) ); if ( acct ) mAccountsToDelete.append( acct ); } if ( !acct ) { // ### FIXME: see above KMessageBox::sorry( this, i18n("Unable to locate account %1.") .arg(listItem->text(0)) ); return; } QListViewItem * item = listItem->itemBelow(); if ( !item ) item = listItem->itemAbove(); delete listItem; if ( item ) mAccountList->setSelected( item, true ); emit changed( true ); } void AccountsPage::ReceivingTab::slotEditNotifications() { if(kmkernel->xmlGuiInstance()) KNotifyDialog::configure(this, 0, kmkernel->xmlGuiInstance()->aboutData()); else KNotifyDialog::configure(this); } void AccountsPage::ReceivingTab::doLoadFromGlobalSettings() { mVerboseNotificationCheck->setChecked( GlobalSettings::self()->verboseNewMailNotification() ); } void AccountsPage::ReceivingTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General" ); mAccountList->clear(); QListViewItem *top = 0; for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0; a = kmkernel->acctMgr()->next() ) { QListViewItem *listItem = new QListViewItem( mAccountList, top, a->name(), a->type() ); if( a->folder() ) listItem->setText( 2, a->folder()->label() ); top = listItem; } QListViewItem *listItem = mAccountList->firstChild(); if ( listItem ) { mAccountList->setCurrentItem( listItem ); mAccountList->setSelected( listItem, true ); } mBeepNewMailCheck->setChecked( general.readBoolEntry("beep-on-mail", false ) ); mCheckmailStartupCheck->setChecked( general.readBoolEntry("checkmail-startup", false) ); QTimer::singleShot( 0, this, SLOT( slotTweakAccountList() ) ); } void AccountsPage::ReceivingTab::slotTweakAccountList() { // Force the contentsWidth of mAccountList to be recalculated so that items can be // selected in the normal way. It would be best if this were not necessary. mAccountList->resizeContents( mAccountList->visibleWidth(), mAccountList->contentsHeight() ); } void AccountsPage::ReceivingTab::save() { // Add accounts marked as new QValueList< QGuardedPtr >::Iterator it; for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) { kmkernel->acctMgr()->add( *it ); // calls installTimer too } // Update accounts that have been modified QValueList::Iterator j; for ( j = mModifiedAccounts.begin() ; j != mModifiedAccounts.end() ; ++j ) { (*j)->oldAccount->pseudoAssign( (*j)->newAccount ); delete (*j)->newAccount; delete (*j); } mModifiedAccounts.clear(); // Delete accounts marked for deletion for ( it = mAccountsToDelete.begin() ; it != mAccountsToDelete.end() ; ++it ) { kmkernel->acctMgr()->writeConfig( true ); if ( (*it) && !kmkernel->acctMgr()->remove(*it) ) KMessageBox::sorry( this, i18n("Unable to locate account %1.") .arg( (*it)->name() ) ); } mAccountsToDelete.clear(); // Incoming mail kmkernel->acctMgr()->writeConfig( false ); kmkernel->cleanupImapFolders(); // Save Mail notification settings KConfigGroup general( KMKernel::config(), "General" ); general.writeEntry( "beep-on-mail", mBeepNewMailCheck->isChecked() ); GlobalSettings::self()->setVerboseNewMailNotification( mVerboseNotificationCheck->isChecked() ); general.writeEntry( "checkmail-startup", mCheckmailStartupCheck->isChecked() ); // Sync new IMAP accounts ASAP: for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) { KMAccount *macc = (*it); ImapAccountBase *acc = dynamic_cast (macc); if ( acc ) { AccountUpdater *au = new AccountUpdater( acc ); au->update(); } } mNewAccounts.clear(); } // ************************************************************* // * * // * AppearancePage * // * * // ************************************************************* QString AppearancePage::helpAnchor() const { return QString::fromLatin1("configure-appearance"); } AppearancePage::AppearancePage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { // // "Fonts" tab: // mFontsTab = new FontsTab(); addTab( mFontsTab, i18n("&Fonts") ); // // "Colors" tab: // mColorsTab = new ColorsTab(); addTab( mColorsTab, i18n("Color&s") ); // // "Layout" tab: // mLayoutTab = new LayoutTab(); addTab( mLayoutTab, i18n("La&yout") ); // // "Headers" tab: // mHeadersTab = new HeadersTab(); addTab( mHeadersTab, i18n("M&essage List") ); // // "Reader window" tab: // mReaderTab = new ReaderTab(); addTab( mReaderTab, i18n("Message W&indow") ); // // "System Tray" tab: // mSystemTrayTab = new SystemTrayTab(); addTab( mSystemTrayTab, i18n("System &Tray") ); load(); } QString AppearancePage::FontsTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-fonts"); } static const struct { const char * configName; const char * displayName; bool enableFamilyAndSize; bool onlyFixed; } fontNames[] = { { "body-font", I18N_NOOP("Message Body"), true, false }, { "list-font", I18N_NOOP("Message List"), true, false }, { "list-new-font", I18N_NOOP("Message List - New Messages"), true, false }, { "list-unread-font", I18N_NOOP("Message List - Unread Messages"), true, false }, { "list-important-font", I18N_NOOP("Message List - Important Messages"), true, false }, { "list-todo-font", I18N_NOOP("Message List - Todo Messages"), true, false }, { "list-date-font", I18N_NOOP("Message List - Date Field"), true, false }, { "folder-font", I18N_NOOP("Folder List"), true, false }, { "quote1-font", I18N_NOOP("Quoted Text - First Level"), false, false }, { "quote2-font", I18N_NOOP("Quoted Text - Second Level"), false, false }, { "quote3-font", I18N_NOOP("Quoted Text - Third Level"), false, false }, { "fixed-font", I18N_NOOP("Fixed Width Font"), true, true }, { "composer-font", I18N_NOOP("Composer"), true, false }, { "print-font", I18N_NOOP("Printing Output"), true, false }, }; static const int numFontNames = sizeof fontNames / sizeof *fontNames; AppearancePageFontsTab::AppearancePageFontsTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ), mActiveFontIndex( -1 ) { assert( numFontNames == sizeof mFont / sizeof *mFont ); // tmp. vars: QVBoxLayout *vlay; QHBoxLayout *hlay; QLabel *label; // "Use custom fonts" checkbox, followed by
vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); mCustomFontCheck = new QCheckBox( i18n("&Use custom fonts"), this ); vlay->addWidget( mCustomFontCheck ); vlay->addWidget( new KSeparator( KSeparator::HLine, this ) ); connect ( mCustomFontCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "font location" combo box and label: hlay = new QHBoxLayout( vlay ); // inherites spacing mFontLocationCombo = new QComboBox( false, this ); mFontLocationCombo->setEnabled( false ); // !mCustomFontCheck->isChecked() QStringList fontDescriptions; for ( int i = 0 ; i < numFontNames ; i++ ) fontDescriptions << i18n( fontNames[i].displayName ); mFontLocationCombo->insertStringList( fontDescriptions ); label = new QLabel( mFontLocationCombo, i18n("Apply &to:"), this ); label->setEnabled( false ); // since !mCustomFontCheck->isChecked() hlay->addWidget( label ); hlay->addWidget( mFontLocationCombo ); hlay->addStretch( 10 ); vlay->addSpacing( KDialog::spacingHint() ); mFontChooser = new KFontChooser( this, "font", false, QStringList(), false, 4 ); mFontChooser->setEnabled( false ); // since !mCustomFontCheck->isChecked() vlay->addWidget( mFontChooser ); connect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ), this, SLOT( slotEmitChanged( void ) ) ); // {en,dis}able widgets depending on the state of mCustomFontCheck: connect( mCustomFontCheck, SIGNAL(toggled(bool)), label, SLOT(setEnabled(bool)) ); connect( mCustomFontCheck, SIGNAL(toggled(bool)), mFontLocationCombo, SLOT(setEnabled(bool)) ); connect( mCustomFontCheck, SIGNAL(toggled(bool)), mFontChooser, SLOT(setEnabled(bool)) ); // load the right font settings into mFontChooser: connect( mFontLocationCombo, SIGNAL(activated(int) ), this, SLOT(slotFontSelectorChanged(int)) ); } void AppearancePage::FontsTab::slotFontSelectorChanged( int index ) { kdDebug(5006) << "slotFontSelectorChanged() called" << endl; if( index < 0 || index >= mFontLocationCombo->count() ) return; // Should never happen, but it is better to check. // Save current fontselector setting before we install the new: if( mActiveFontIndex == 0 ) { mFont[0] = mFontChooser->font(); // hardcode the family and size of "message body" dependant fonts: for ( int i = 0 ; i < numFontNames ; i++ ) if ( !fontNames[i].enableFamilyAndSize ) { // ### shall we copy the font and set the save and re-set // {regular,italic,bold,bold italic} property or should we // copy only family and pointSize? mFont[i].setFamily( mFont[0].family() ); mFont[i].setPointSize/*Float?*/( mFont[0].pointSize/*Float?*/() ); } } else if ( mActiveFontIndex > 0 ) mFont[ mActiveFontIndex ] = mFontChooser->font(); mActiveFontIndex = index; // Disonnect so the "Apply" button is not activated by the change disconnect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ), this, SLOT( slotEmitChanged( void ) ) ); // Display the new setting: mFontChooser->setFont( mFont[index], fontNames[index].onlyFixed ); connect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ), this, SLOT( slotEmitChanged( void ) ) ); // Disable Family and Size list if we have selected a quote font: mFontChooser->enableColumn( KFontChooser::FamilyList|KFontChooser::SizeList, fontNames[ index ].enableFamilyAndSize ); } void AppearancePage::FontsTab::doLoadOther() { KConfigGroup fonts( KMKernel::config(), "Fonts" ); mFont[0] = KGlobalSettings::generalFont(); QFont fixedFont = KGlobalSettings::fixedFont(); for ( int i = 0 ; i < numFontNames ; i++ ) mFont[i] = fonts.readFontEntry( fontNames[i].configName, (fontNames[i].onlyFixed) ? &fixedFont : &mFont[0] ); mCustomFontCheck->setChecked( !fonts.readBoolEntry( "defaultFonts", true ) ); mFontLocationCombo->setCurrentItem( 0 ); slotFontSelectorChanged( 0 ); } void AppearancePage::FontsTab::installProfile( KConfig * profile ) { KConfigGroup fonts( profile, "Fonts" ); // read fonts that are defined in the profile: bool needChange = false; for ( int i = 0 ; i < numFontNames ; i++ ) if ( fonts.hasKey( fontNames[i].configName ) ) { needChange = true; mFont[i] = fonts.readFontEntry( fontNames[i].configName ); kdDebug(5006) << "got font \"" << fontNames[i].configName << "\" thusly: \"" << mFont[i].toString() << "\"" << endl; } if ( needChange && mFontLocationCombo->currentItem() > 0 ) mFontChooser->setFont( mFont[ mFontLocationCombo->currentItem() ], fontNames[ mFontLocationCombo->currentItem() ].onlyFixed ); if ( fonts.hasKey( "defaultFonts" ) ) mCustomFontCheck->setChecked( !fonts.readBoolEntry( "defaultFonts" ) ); } void AppearancePage::FontsTab::save() { KConfigGroup fonts( KMKernel::config(), "Fonts" ); // read the current font (might have been modified) if ( mActiveFontIndex >= 0 ) mFont[ mActiveFontIndex ] = mFontChooser->font(); bool customFonts = mCustomFontCheck->isChecked(); fonts.writeEntry( "defaultFonts", !customFonts ); for ( int i = 0 ; i < numFontNames ; i++ ) if ( customFonts || fonts.hasKey( fontNames[i].configName ) ) // Don't write font info when we use default fonts, but write // if it's already there: fonts.writeEntry( fontNames[i].configName, mFont[i] ); } QString AppearancePage::ColorsTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-colors"); } static const struct { const char * configName; const char * displayName; } colorNames[] = { // adjust setup() if you change this: { "BackgroundColor", I18N_NOOP("Composer Background") }, { "AltBackgroundColor", I18N_NOOP("Alternative Background Color") }, { "ForegroundColor", I18N_NOOP("Normal Text") }, { "QuotedText1", I18N_NOOP("Quoted Text - First Level") }, { "QuotedText2", I18N_NOOP("Quoted Text - Second Level") }, { "QuotedText3", I18N_NOOP("Quoted Text - Third Level") }, { "LinkColor", I18N_NOOP("Link") }, { "FollowedColor", I18N_NOOP("Followed Link") }, { "MisspelledColor", I18N_NOOP("Misspelled Words") }, { "NewMessage", I18N_NOOP("New Message") }, { "UnreadMessage", I18N_NOOP("Unread Message") }, { "FlagMessage", I18N_NOOP("Important Message") }, { "TodoMessage", I18N_NOOP("Todo Message") }, { "PGPMessageEncr", I18N_NOOP("OpenPGP Message - Encrypted") }, { "PGPMessageOkKeyOk", I18N_NOOP("OpenPGP Message - Valid Signature with Trusted Key") }, { "PGPMessageOkKeyBad", I18N_NOOP("OpenPGP Message - Valid Signature with Untrusted Key") }, { "PGPMessageWarn", I18N_NOOP("OpenPGP Message - Unchecked Signature") }, { "PGPMessageErr", I18N_NOOP("OpenPGP Message - Bad Signature") }, { "HTMLWarningColor", I18N_NOOP("Border Around Warning Prepending HTML Messages") }, { "CloseToQuotaColor", I18N_NOOP("Folder Name and Size When Close to Quota") }, { "ColorbarBackgroundPlain", I18N_NOOP("HTML Status Bar Background - No HTML Message") }, { "ColorbarForegroundPlain", I18N_NOOP("HTML Status Bar Foreground - No HTML Message") }, { "ColorbarBackgroundHTML", I18N_NOOP("HTML Status Bar Background - HTML Message") }, { "ColorbarForegroundHTML", I18N_NOOP("HTML Status Bar Foreground - HTML Message") }, }; static const int numColorNames = sizeof colorNames / sizeof *colorNames; AppearancePageColorsTab::AppearancePageColorsTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; // "use custom colors" check box vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); mCustomColorCheck = new QCheckBox( i18n("&Use custom colors"), this ); vlay->addWidget( mCustomColorCheck ); connect( mCustomColorCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // color list box: mColorList = new ColorListBox( this ); mColorList->setEnabled( false ); // since !mCustomColorCheck->isChecked() QStringList modeList; for ( int i = 0 ; i < numColorNames ; i++ ) mColorList->insertItem( new ColorListItem( i18n( colorNames[i].displayName ) ) ); vlay->addWidget( mColorList, 1 ); // "recycle colors" check box: mRecycleColorCheck = new QCheckBox( i18n("Recycle colors on deep "ing"), this ); mRecycleColorCheck->setEnabled( false ); vlay->addWidget( mRecycleColorCheck ); connect( mRecycleColorCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // close to quota threshold QHBoxLayout *hbox = new QHBoxLayout(vlay); QLabel *l = new QLabel( i18n("Close to quota threshold"), this ); hbox->addWidget( l ); l->setEnabled( false ); mCloseToQuotaThreshold = new QSpinBox( 0, 100, 1, this ); connect( mCloseToQuotaThreshold, SIGNAL( valueChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mCloseToQuotaThreshold->setEnabled( false ); mCloseToQuotaThreshold->setSuffix( i18n("%")); hbox->addWidget( mCloseToQuotaThreshold ); hbox->addWidget( new QWidget(this), 2 ); // {en,dir}able widgets depending on the state of mCustomColorCheck: connect( mCustomColorCheck, SIGNAL(toggled(bool)), mColorList, SLOT(setEnabled(bool)) ); connect( mCustomColorCheck, SIGNAL(toggled(bool)), mRecycleColorCheck, SLOT(setEnabled(bool)) ); connect( mCustomColorCheck, SIGNAL(toggled(bool)), l, SLOT(setEnabled(bool)) ); connect( mCustomColorCheck, SIGNAL(toggled(bool)), mCloseToQuotaThreshold, SLOT(setEnabled(bool)) ); connect( mCustomColorCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); } void AppearancePage::ColorsTab::doLoadOther() { KConfigGroup reader( KMKernel::config(), "Reader" ); mCustomColorCheck->setChecked( !reader.readBoolEntry( "defaultColors", true ) ); mRecycleColorCheck->setChecked( reader.readBoolEntry( "RecycleQuoteColors", false ) ); mCloseToQuotaThreshold->setValue( GlobalSettings::closeToQuotaThreshold() ); static const QColor defaultColor[ numColorNames ] = { kapp->palette().active().base(), // bg KGlobalSettings::alternateBackgroundColor(), // alt bg kapp->palette().active().text(), // fg QColor( 0x00, 0x80, 0x00 ), // quoted l1 QColor( 0x00, 0x70, 0x00 ), // quoted l2 QColor( 0x00, 0x60, 0x00 ), // quoted l3 KGlobalSettings::linkColor(), // link KGlobalSettings::visitedLinkColor(), // visited link Qt::red, // misspelled words Qt::red, // new msg Qt::blue, // unread mgs QColor( 0x00, 0x7F, 0x00 ), // important msg Qt::blue, // todo mgs QColor( 0x00, 0x80, 0xFF ), // light blue // pgp encrypted QColor( 0x40, 0xFF, 0x40 ), // light green // pgp ok, trusted key QColor( 0xFF, 0xFF, 0x40 ), // light yellow // pgp ok, untrusted key QColor( 0xFF, 0xFF, 0x40 ), // light yellow // pgp unchk Qt::red, // pgp bad QColor( 0xFF, 0x40, 0x40 ), // warning text color: light red Qt::red, // close to quota Qt::lightGray, // colorbar plain bg Qt::black, // colorbar plain fg Qt::black, // colorbar html bg Qt::white, // colorbar html fg }; for ( int i = 0 ; i < numColorNames ; i++ ) { mColorList->setColor( i, reader.readColorEntry( colorNames[i].configName, &defaultColor[i] ) ); } connect( mColorList, SIGNAL( changed( ) ), this, SLOT( slotEmitChanged( void ) ) ); } void AppearancePage::ColorsTab::installProfile( KConfig * profile ) { KConfigGroup reader( profile, "Reader" ); if ( reader.hasKey( "defaultColors" ) ) mCustomColorCheck->setChecked( !reader.readBoolEntry( "defaultColors" ) ); if ( reader.hasKey( "RecycleQuoteColors" ) ) mRecycleColorCheck->setChecked( reader.readBoolEntry( "RecycleQuoteColors" ) ); for ( int i = 0 ; i < numColorNames ; i++ ) if ( reader.hasKey( colorNames[i].configName ) ) mColorList->setColor( i, reader.readColorEntry( colorNames[i].configName ) ); } void AppearancePage::ColorsTab::save() { KConfigGroup reader( KMKernel::config(), "Reader" ); bool customColors = mCustomColorCheck->isChecked(); reader.writeEntry( "defaultColors", !customColors ); for ( int i = 0 ; i < numColorNames ; i++ ) // Don't write color info when we use default colors, but write // if it's already there: if ( customColors || reader.hasKey( colorNames[i].configName ) ) reader.writeEntry( colorNames[i].configName, mColorList->color(i) ); reader.writeEntry( "RecycleQuoteColors", mRecycleColorCheck->isChecked() ); GlobalSettings::setCloseToQuotaThreshold( mCloseToQuotaThreshold->value() ); } QString AppearancePage::LayoutTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-layout"); } static const EnumConfigEntryItem folderListModes[] = { { "long", I18N_NOOP("Lon&g folder list") }, { "short", I18N_NOOP("Shor&t folder list" ) } }; static const EnumConfigEntry folderListMode = { "Geometry", "FolderList", I18N_NOOP("Folder List"), folderListModes, DIM(folderListModes), 0 }; static const EnumConfigEntryItem mimeTreeLocations[] = { { "top", I18N_NOOP("Abo&ve the message pane") }, { "bottom", I18N_NOOP("&Below the message pane") } }; static const EnumConfigEntry mimeTreeLocation = { "Reader", "MimeTreeLocation", I18N_NOOP("Message Structure Viewer Placement"), mimeTreeLocations, DIM(mimeTreeLocations), 1 }; static const EnumConfigEntryItem mimeTreeModes[] = { { "never", I18N_NOOP("Show &never") }, { "smart", I18N_NOOP("Show only for non-plaintext &messages") }, { "always", I18N_NOOP("Show alway&s") } }; static const EnumConfigEntry mimeTreeMode = { "Reader", "MimeTreeMode", I18N_NOOP("Message Structure Viewer"), mimeTreeModes, DIM(mimeTreeModes), 1 }; static const EnumConfigEntryItem readerWindowModes[] = { { "hide", I18N_NOOP("&Do not show a message preview pane") }, { "below", I18N_NOOP("Show the message preview pane belo&w the message list") }, { "right", I18N_NOOP("Show the message preview pane ne&xt to the message list") } }; static const EnumConfigEntry readerWindowMode = { "Geometry", "readerWindowMode", I18N_NOOP("Message Preview Pane"), readerWindowModes, DIM(readerWindowModes), 1 }; AppearancePageLayoutTab::AppearancePageLayoutTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout * vlay; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "folder list" radio buttons: populateButtonGroup( mFolderListGroup = new QHButtonGroup( this ), folderListMode ); vlay->addWidget( mFolderListGroup ); connect( mFolderListGroup, SIGNAL ( clicked( int ) ), this, SLOT( slotEmitChanged() ) ); mFavoriteFolderViewCB = new QCheckBox( i18n("Show favorite folder view"), this ); connect( mFavoriteFolderViewCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); vlay->addWidget( mFavoriteFolderViewCB ); // "show reader window" radio buttons: populateButtonGroup( mReaderWindowModeGroup = new QVButtonGroup( this ), readerWindowMode ); vlay->addWidget( mReaderWindowModeGroup ); connect( mReaderWindowModeGroup, SIGNAL ( clicked( int ) ), this, SLOT( slotEmitChanged() ) ); // "Show MIME Tree" radio buttons: populateButtonGroup( mMIMETreeModeGroup = new QVButtonGroup( this ), mimeTreeMode ); vlay->addWidget( mMIMETreeModeGroup ); connect( mMIMETreeModeGroup, SIGNAL ( clicked( int ) ), this, SLOT( slotEmitChanged() ) ); // "MIME Tree Location" radio buttons: populateButtonGroup( mMIMETreeLocationGroup = new QHButtonGroup( this ), mimeTreeLocation ); vlay->addWidget( mMIMETreeLocationGroup ); connect( mMIMETreeLocationGroup, SIGNAL ( clicked( int ) ), this, SLOT( slotEmitChanged() ) ); vlay->addStretch( 10 ); // spacer } void AppearancePage::LayoutTab::doLoadOther() { const KConfigGroup reader( KMKernel::config(), "Reader" ); const KConfigGroup geometry( KMKernel::config(), "Geometry" ); loadWidget( mFolderListGroup, geometry, folderListMode ); loadWidget( mMIMETreeLocationGroup, reader, mimeTreeLocation ); loadWidget( mMIMETreeModeGroup, reader, mimeTreeMode ); loadWidget( mReaderWindowModeGroup, geometry, readerWindowMode ); mFavoriteFolderViewCB->setChecked( GlobalSettings::self()->enableFavoriteFolderView() ); } void AppearancePage::LayoutTab::installProfile( KConfig * profile ) { const KConfigGroup reader( profile, "Reader" ); const KConfigGroup geometry( profile, "Geometry" ); loadProfile( mFolderListGroup, geometry, folderListMode ); loadProfile( mMIMETreeLocationGroup, reader, mimeTreeLocation ); loadProfile( mMIMETreeModeGroup, reader, mimeTreeMode ); loadProfile( mReaderWindowModeGroup, geometry, readerWindowMode ); } void AppearancePage::LayoutTab::save() { KConfigGroup reader( KMKernel::config(), "Reader" ); KConfigGroup geometry( KMKernel::config(), "Geometry" ); saveButtonGroup( mFolderListGroup, geometry, folderListMode ); saveButtonGroup( mMIMETreeLocationGroup, reader, mimeTreeLocation ); saveButtonGroup( mMIMETreeModeGroup, reader, mimeTreeMode ); saveButtonGroup( mReaderWindowModeGroup, geometry, readerWindowMode ); GlobalSettings::self()->setEnableFavoriteFolderView( mFavoriteFolderViewCB->isChecked() ); } // // Appearance Message List // QString AppearancePage::HeadersTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-headers"); } static const struct { const char * displayName; DateFormatter::FormatType dateDisplay; } dateDisplayConfig[] = { { I18N_NOOP("Sta&ndard format (%1)"), KMime::DateFormatter::CTime }, { I18N_NOOP("Locali&zed format (%1)"), KMime::DateFormatter::Localized }, { I18N_NOOP("Fancy for&mat (%1)"), KMime::DateFormatter::Fancy }, { I18N_NOOP("C&ustom format (Shift+F1 for help):"), KMime::DateFormatter::Custom } }; static const int numDateDisplayConfig = sizeof dateDisplayConfig / sizeof *dateDisplayConfig; AppearancePageHeadersTab::AppearancePageHeadersTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ), mCustomDateFormatEdit( 0 ) { // tmp. vars: QButtonGroup * group; QRadioButton * radio; QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "General Options" group: group = new QVButtonGroup( i18n( "General Options" ), this ); group->layout()->setSpacing( KDialog::spacingHint() ); mMessageSizeCheck = new QCheckBox( i18n("Display messa&ge sizes"), group ); mCryptoIconsCheck = new QCheckBox( i18n( "Show crypto &icons" ), group ); mAttachmentCheck = new QCheckBox( i18n("Show attachment icon"), group ); mNestedMessagesCheck = new QCheckBox( i18n("&Threaded message list"), group ); connect( mMessageSizeCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mAttachmentCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mCryptoIconsCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mNestedMessagesCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( group ); // "Message Header Threading Options" group: mNestingPolicy = new QVButtonGroup( i18n("Threaded Message List Options"), this ); mNestingPolicy->layout()->setSpacing( KDialog::spacingHint() ); mNestingPolicy->insert( new QRadioButton( i18n("Always &keep threads open"), mNestingPolicy ), 0 ); mNestingPolicy->insert( new QRadioButton( i18n("Threads default to o&pen"), mNestingPolicy ), 1 ); mNestingPolicy->insert( new QRadioButton( i18n("Threads default to closed"), mNestingPolicy ), 2 ); mNestingPolicy->insert( new QRadioButton( i18n("Open threads that contain ne&w, unread " "or important messages and open watched threads."), mNestingPolicy ), 3 ); vlay->addWidget( mNestingPolicy ); connect( mNestingPolicy, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "Date Display" group: mDateDisplay = new QVButtonGroup( i18n("Date Display"), this ); mDateDisplay->layout()->setSpacing( KDialog::spacingHint() ); for ( int i = 0 ; i < numDateDisplayConfig ; i++ ) { QString buttonLabel = i18n(dateDisplayConfig[i].displayName); if ( buttonLabel.contains("%1") ) buttonLabel = buttonLabel.arg( DateFormatter::formatCurrentDate( dateDisplayConfig[i].dateDisplay ) ); radio = new QRadioButton( buttonLabel, mDateDisplay ); mDateDisplay->insert( radio, i ); if ( dateDisplayConfig[i].dateDisplay == DateFormatter::Custom ) { mCustomDateFormatEdit = new KLineEdit( mDateDisplay ); mCustomDateFormatEdit->setEnabled( false ); connect( radio, SIGNAL(toggled(bool)), mCustomDateFormatEdit, SLOT(setEnabled(bool)) ); connect( mCustomDateFormatEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotEmitChanged(void)) ); QString customDateWhatsThis = i18n("

These expressions may be used for the date:" "

" "
    " "
  • d - the day as a number without a leading zero (1-31)
  • " "
  • dd - the day as a number with a leading zero (01-31)
  • " "
  • ddd - the abbreviated day name (Mon - Sun)
  • " "
  • dddd - the long day name (Monday - Sunday)
  • " "
  • M - the month as a number without a leading zero (1-12)
  • " "
  • MM - the month as a number with a leading zero (01-12)
  • " "
  • MMM - the abbreviated month name (Jan - Dec)
  • " "
  • MMMM - the long month name (January - December)
  • " "
  • yy - the year as a two digit number (00-99)
  • " "
  • yyyy - the year as a four digit number (0000-9999)
  • " "
" "

These expressions may be used for the time:" "

" "
    " "
  • h - the hour without a leading zero (0-23 or 1-12 if AM/PM display)
  • " "
  • hh - the hour with a leading zero (00-23 or 01-12 if AM/PM display)
  • " "
  • m - the minutes without a leading zero (0-59)
  • " "
  • mm - the minutes with a leading zero (00-59)
  • " "
  • s - the seconds without a leading zero (0-59)
  • " "
  • ss - the seconds with a leading zero (00-59)
  • " "
  • z - the milliseconds without leading zeroes (0-999)
  • " "
  • zzz - the milliseconds with leading zeroes (000-999)
  • " "
  • AP - switch to AM/PM display. AP will be replaced by either \"AM\" or \"PM\".
  • " "
  • ap - switch to AM/PM display. ap will be replaced by either \"am\" or \"pm\".
  • " "
  • Z - time zone in numeric form (-0500)
  • " "
" "

All other input characters will be ignored." "

"); QWhatsThis::add( mCustomDateFormatEdit, customDateWhatsThis ); QWhatsThis::add( radio, customDateWhatsThis ); } } // end for loop populating mDateDisplay vlay->addWidget( mDateDisplay ); connect( mDateDisplay, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addStretch( 10 ); // spacer } void AppearancePage::HeadersTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General" ); KConfigGroup geometry( KMKernel::config(), "Geometry" ); // "General Options": mNestedMessagesCheck->setChecked( geometry.readBoolEntry( "nestedMessages", false ) ); mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize", false ) ); mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons", false ) ); mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon", true ) ); // "Message Header Threading Options": int num = geometry.readNumEntry( "nestingPolicy", 3 ); if ( num < 0 || num > 3 ) num = 3; mNestingPolicy->setButton( num ); // "Date Display": setDateDisplay( general.readNumEntry( "dateFormat", DateFormatter::Fancy ), general.readEntry( "customDateFormat" ) ); } void AppearancePage::HeadersTab::setDateDisplay( int num, const QString & format ) { DateFormatter::FormatType dateDisplay = static_cast( num ); // special case: needs text for the line edit: if ( dateDisplay == DateFormatter::Custom ) mCustomDateFormatEdit->setText( format ); for ( int i = 0 ; i < numDateDisplayConfig ; i++ ) if ( dateDisplay == dateDisplayConfig[i].dateDisplay ) { mDateDisplay->setButton( i ); return; } // fell through since none found: mDateDisplay->setButton( numDateDisplayConfig - 2 ); // default } void AppearancePage::HeadersTab::installProfile( KConfig * profile ) { KConfigGroup general( profile, "General" ); KConfigGroup geometry( profile, "Geometry" ); if ( geometry.hasKey( "nestedMessages" ) ) mNestedMessagesCheck->setChecked( geometry.readBoolEntry( "nestedMessages" ) ); if ( general.hasKey( "showMessageSize" ) ) mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize" ) ); if( general.hasKey( "showCryptoIcons" ) ) mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons" ) ); if ( general.hasKey( "showAttachmentIcon" ) ) mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon" ) ); if ( geometry.hasKey( "nestingPolicy" ) ) { int num = geometry.readNumEntry( "nestingPolicy" ); if ( num < 0 || num > 3 ) num = 3; mNestingPolicy->setButton( num ); } if ( general.hasKey( "dateFormat" ) ) setDateDisplay( general.readNumEntry( "dateFormat" ), general.readEntry( "customDateFormat" ) ); } void AppearancePage::HeadersTab::save() { KConfigGroup general( KMKernel::config(), "General" ); KConfigGroup geometry( KMKernel::config(), "Geometry" ); if ( geometry.readBoolEntry( "nestedMessages", false ) != mNestedMessagesCheck->isChecked() ) { int result = KMessageBox::warningContinueCancel( this, i18n("Changing the global threading setting will override " "all folder specific values."), QString::null, KStdGuiItem::cont(), "threadOverride" ); if ( result == KMessageBox::Continue ) { geometry.writeEntry( "nestedMessages", mNestedMessagesCheck->isChecked() ); // remove all threadMessagesOverride keys from all [Folder-*] groups: QStringList groups = KMKernel::config()->groupList().grep( QRegExp("^Folder-") ); kdDebug(5006) << "groups.count() == " << groups.count() << endl; for ( QStringList::const_iterator it = groups.begin() ; it != groups.end() ; ++it ) { KConfigGroup group( KMKernel::config(), *it ); group.deleteEntry( "threadMessagesOverride" ); } } } geometry.writeEntry( "nestingPolicy", mNestingPolicy->id( mNestingPolicy->selected() ) ); general.writeEntry( "showMessageSize", mMessageSizeCheck->isChecked() ); general.writeEntry( "showCryptoIcons", mCryptoIconsCheck->isChecked() ); general.writeEntry( "showAttachmentIcon", mAttachmentCheck->isChecked() ); int dateDisplayID = mDateDisplay->id( mDateDisplay->selected() ); // check bounds: assert( dateDisplayID >= 0 ); assert( dateDisplayID < numDateDisplayConfig ); general.writeEntry( "dateFormat", dateDisplayConfig[ dateDisplayID ].dateDisplay ); general.writeEntry( "customDateFormat", mCustomDateFormatEdit->text() ); } // // Message Window // static const BoolConfigEntry closeAfterReplyOrForward = { "Reader", "CloseAfterReplyOrForward", I18N_NOOP("Close message window after replying or forwarding"), false }; static const BoolConfigEntry showColorbarMode = { "Reader", "showColorbar", I18N_NOOP("Show HTML stat&us bar"), false }; static const BoolConfigEntry showSpamStatusMode = { "Reader", "showSpamStatus", I18N_NOOP("Show s&pam status in fancy headers"), true }; static const BoolConfigEntry showEmoticons = { "Reader", "ShowEmoticons", I18N_NOOP("Replace smileys by emoticons"), true }; static const BoolConfigEntry shrinkQuotes = { "Reader", "ShrinkQuotes", I18N_NOOP("Use smaller font for quoted text"), false }; static const BoolConfigEntry showExpandQuotesMark= { "Reader", "ShowExpandQuotesMark", I18N_NOOP("Show expand/collapse quote marks"), false }; QString AppearancePage::ReaderTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-reader"); } AppearancePageReaderTab::AppearancePageReaderTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { QVBoxLayout *vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "close message window after replying or forwarding" checkbox populateCheckBox( mCloseAfterReplyOrForwardCheck = new QCheckBox( this ), closeAfterReplyOrForward ); QToolTip::add( mCloseAfterReplyOrForwardCheck, i18n( "Close the standalone message window after replying or forwarding the message" ) ); vlay->addWidget( mCloseAfterReplyOrForwardCheck ); connect( mCloseAfterReplyOrForwardCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "show colorbar" check box: populateCheckBox( mShowColorbarCheck = new QCheckBox( this ), showColorbarMode ); vlay->addWidget( mShowColorbarCheck ); connect( mShowColorbarCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "show spam status" check box; populateCheckBox( mShowSpamStatusCheck = new QCheckBox( this ), showSpamStatusMode ); vlay->addWidget( mShowSpamStatusCheck ); connect( mShowSpamStatusCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "replace smileys by emoticons" check box; populateCheckBox( mShowEmoticonsCheck = new QCheckBox( this ), showEmoticons ); vlay->addWidget( mShowEmoticonsCheck ); connect( mShowEmoticonsCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "Use smaller font for quoted text" check box mShrinkQuotesCheck = new QCheckBox( i18n( shrinkQuotes.desc ), this, "kcfg_ShrinkQuotes" ); vlay->addWidget( mShrinkQuotesCheck ); connect( mShrinkQuotesCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "Show expand/collaps quote marks" check box; QHBoxLayout *hlay= new QHBoxLayout( vlay ); // inherits spacing populateCheckBox( mShowExpandQuotesMark= new QCheckBox( this ), showExpandQuotesMark); hlay->addWidget( mShowExpandQuotesMark); connect( mShowExpandQuotesMark, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); hlay->addStretch( 1 ); mCollapseQuoteLevelSpin = new KIntSpinBox( 0/*min*/,10/*max*/,1/*step*/, 3/*init*/,10/*base*/,this ); QLabel *label = new QLabel( mCollapseQuoteLevelSpin, GlobalSettings::self()->collapseQuoteLevelSpinItem()->label(), this ); hlay->addWidget( label ); mCollapseQuoteLevelSpin->setEnabled( false ); //since !mShowExpandQuotesMark->isCheckec() connect( mCollapseQuoteLevelSpin, SIGNAL( valueChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); hlay->addWidget( mCollapseQuoteLevelSpin); connect( mShowExpandQuotesMark, SIGNAL( toggled( bool ) ), mCollapseQuoteLevelSpin, SLOT( setEnabled( bool ) ) ); // Fallback Character Encoding hlay = new QHBoxLayout( vlay ); // inherits spacing mCharsetCombo = new QComboBox( this ); mCharsetCombo->insertStringList( KMMsgBase::supportedEncodings( false ) ); connect( mCharsetCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); QString fallbackCharsetWhatsThis = i18n( GlobalSettings::self()->fallbackCharacterEncodingItem()->whatsThis().utf8() ); QWhatsThis::add( mCharsetCombo, fallbackCharsetWhatsThis ); label = new QLabel( i18n("Fallback ch&aracter encoding:"), this ); label->setBuddy( mCharsetCombo ); hlay->addWidget( label ); hlay->addWidget( mCharsetCombo ); // Override Character Encoding QHBoxLayout *hlay2 = new QHBoxLayout( vlay ); // inherits spacing mOverrideCharsetCombo = new QComboBox( this ); QStringList encodings = KMMsgBase::supportedEncodings( false ); encodings.prepend( i18n( "Auto" ) ); mOverrideCharsetCombo->insertStringList( encodings ); mOverrideCharsetCombo->setCurrentItem(0); connect( mOverrideCharsetCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); QString overrideCharsetWhatsThis = i18n( GlobalSettings::self()->overrideCharacterEncodingItem()->whatsThis().utf8() ); QWhatsThis::add( mOverrideCharsetCombo, overrideCharsetWhatsThis ); label = new QLabel( i18n("&Override character encoding:"), this ); label->setBuddy( mOverrideCharsetCombo ); hlay2->addWidget( label ); hlay2->addWidget( mOverrideCharsetCombo ); vlay->addStretch( 100 ); // spacer } void AppearancePage::ReaderTab::readCurrentFallbackCodec() { QStringList encodings = KMMsgBase::supportedEncodings( false ); QStringList::ConstIterator it( encodings.begin() ); QStringList::ConstIterator end( encodings.end() ); QString currentEncoding = GlobalSettings::self()->fallbackCharacterEncoding(); currentEncoding = currentEncoding.replace( "iso ", "iso-", false ); ///kdDebug(5006) << "Looking for encoding: " << currentEncoding << endl; int i = 0; int indexOfLatin9 = 0; bool found = false; for( ; it != end; ++it) { const QString encoding = KGlobal::charsets()->encodingForName(*it); if ( encoding == "iso-8859-15" ) indexOfLatin9 = i; if( encoding == currentEncoding ) { mCharsetCombo->setCurrentItem( i ); found = true; break; } i++; } if ( !found ) // nothing matched, use latin9 mCharsetCombo->setCurrentItem( indexOfLatin9 ); } void AppearancePage::ReaderTab::readCurrentOverrideCodec() { const QString ¤tOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding(); if ( currentOverrideEncoding.isEmpty() ) { mOverrideCharsetCombo->setCurrentItem( 0 ); return; } QStringList encodings = KMMsgBase::supportedEncodings( false ); encodings.prepend( i18n( "Auto" ) ); QStringList::Iterator it( encodings.begin() ); QStringList::Iterator end( encodings.end() ); uint i = 0; for( ; it != end; ++it) { if( KGlobal::charsets()->encodingForName(*it) == currentOverrideEncoding ) { mOverrideCharsetCombo->setCurrentItem( i ); break; } i++; } if ( i == encodings.size() ) { // the current value of overrideCharacterEncoding is an unknown encoding => reset to Auto kdWarning(5006) << "Unknown override character encoding \"" << currentOverrideEncoding << "\". Resetting to Auto." << endl; mOverrideCharsetCombo->setCurrentItem( 0 ); GlobalSettings::self()->setOverrideCharacterEncoding( QString::null ); } } void AppearancePage::ReaderTab::doLoadFromGlobalSettings() { mCloseAfterReplyOrForwardCheck->setChecked( GlobalSettings::self()->closeAfterReplyOrForward() ); mShowEmoticonsCheck->setChecked( GlobalSettings::self()->showEmoticons() ); mShrinkQuotesCheck->setChecked( GlobalSettings::self()->shrinkQuotes() ); mShowExpandQuotesMark->setChecked( GlobalSettings::self()->showExpandQuotesMark() ); mCollapseQuoteLevelSpin->setValue( GlobalSettings::self()->collapseQuoteLevelSpin() ); readCurrentFallbackCodec(); readCurrentOverrideCodec(); } void AppearancePage::ReaderTab::doLoadOther() { const KConfigGroup reader( KMKernel::config(), "Reader" ); loadWidget( mShowColorbarCheck, reader, showColorbarMode ); loadWidget( mShowSpamStatusCheck, reader, showSpamStatusMode ); } void AppearancePage::ReaderTab::save() { KConfigGroup reader( KMKernel::config(), "Reader" ); saveCheckBox( mShowColorbarCheck, reader, showColorbarMode ); saveCheckBox( mShowSpamStatusCheck, reader, showSpamStatusMode ); GlobalSettings::self()->setCloseAfterReplyOrForward( mCloseAfterReplyOrForwardCheck->isChecked() ); GlobalSettings::self()->setShowEmoticons( mShowEmoticonsCheck->isChecked() ); GlobalSettings::self()->setShrinkQuotes( mShrinkQuotesCheck->isChecked() ); GlobalSettings::self()->setShowExpandQuotesMark( mShowExpandQuotesMark->isChecked() ); GlobalSettings::self()->setCollapseQuoteLevelSpin( mCollapseQuoteLevelSpin->value() ); GlobalSettings::self()->setFallbackCharacterEncoding( KGlobal::charsets()->encodingForName( mCharsetCombo->currentText() ) ); GlobalSettings::self()->setOverrideCharacterEncoding( mOverrideCharsetCombo->currentItem() == 0 ? QString() : KGlobal::charsets()->encodingForName( mOverrideCharsetCombo->currentText() ) ); } void AppearancePage::ReaderTab::installProfile( KConfig * /* profile */ ) { const KConfigGroup reader( KMKernel::config(), "Reader" ); loadProfile( mCloseAfterReplyOrForwardCheck, reader, closeAfterReplyOrForward ); loadProfile( mShowColorbarCheck, reader, showColorbarMode ); loadProfile( mShowSpamStatusCheck, reader, showSpamStatusMode ); loadProfile( mShowEmoticonsCheck, reader, showEmoticons ); loadProfile( mShrinkQuotesCheck, reader, shrinkQuotes ); loadProfile( mShowExpandQuotesMark, reader, showExpandQuotesMark); } QString AppearancePage::SystemTrayTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-systemtray"); } AppearancePageSystemTrayTab::AppearancePageSystemTrayTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "Enable system tray applet" check box mSystemTrayCheck = new QCheckBox( i18n("Enable system tray icon"), this ); vlay->addWidget( mSystemTrayCheck ); connect( mSystemTrayCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // System tray modes mSystemTrayGroup = new QVButtonGroup( i18n("System Tray Mode"), this ); mSystemTrayGroup->layout()->setSpacing( KDialog::spacingHint() ); vlay->addWidget( mSystemTrayGroup ); connect( mSystemTrayGroup, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mSystemTrayCheck, SIGNAL( toggled( bool ) ), mSystemTrayGroup, SLOT( setEnabled( bool ) ) ); mSystemTrayGroup->insert( new QRadioButton( i18n("Always show KMail in system tray"), mSystemTrayGroup ), GlobalSettings::EnumSystemTrayPolicy::ShowAlways ); mSystemTrayGroup->insert( new QRadioButton( i18n("Only show KMail in system tray if there are unread messages"), mSystemTrayGroup ), GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ); vlay->addStretch( 10 ); // spacer } void AppearancePage::SystemTrayTab::doLoadFromGlobalSettings() { mSystemTrayCheck->setChecked( GlobalSettings::self()->systemTrayEnabled() ); mSystemTrayGroup->setButton( GlobalSettings::self()->systemTrayPolicy() ); mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() ); } void AppearancePage::SystemTrayTab::installProfile( KConfig * profile ) { KConfigGroup general( profile, "General" ); if ( general.hasKey( "SystemTrayEnabled" ) ) { mSystemTrayCheck->setChecked( general.readBoolEntry( "SystemTrayEnabled" ) ); } if ( general.hasKey( "SystemTrayPolicy" ) ) { mSystemTrayGroup->setButton( general.readNumEntry( "SystemTrayPolicy" ) ); } mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() ); } void AppearancePage::SystemTrayTab::save() { GlobalSettings::self()->setSystemTrayEnabled( mSystemTrayCheck->isChecked() ); GlobalSettings::self()->setSystemTrayPolicy( mSystemTrayGroup->id( mSystemTrayGroup->selected() ) ); } // ************************************************************* // * * // * ComposerPage * // * * // ************************************************************* QString ComposerPage::helpAnchor() const { return QString::fromLatin1("configure-composer"); } ComposerPage::ComposerPage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { // // "General" tab: // mGeneralTab = new GeneralTab(); addTab( mGeneralTab, i18n("&General") ); addConfig( GlobalSettings::self(), mGeneralTab ); // // "Phrases" tab: // // mPhrasesTab = new PhrasesTab(); // addTab( mPhrasesTab, i18n("&Phrases") ); // // "Templates" tab: // mTemplatesTab = new TemplatesTab(); addTab( mTemplatesTab, i18n("&Templates") ); // // "Custom Templates" tab: // mCustomTemplatesTab = new CustomTemplatesTab(); addTab( mCustomTemplatesTab, i18n("&Custom Templates") ); // // "Subject" tab: // mSubjectTab = new SubjectTab(); addTab( mSubjectTab, i18n("&Subject") ); addConfig( GlobalSettings::self(), mSubjectTab ); // // "Charset" tab: // mCharsetTab = new CharsetTab(); addTab( mCharsetTab, i18n("Cha&rset") ); // // "Headers" tab: // mHeadersTab = new HeadersTab(); addTab( mHeadersTab, i18n("H&eaders") ); // // "Attachments" tab: // mAttachmentsTab = new AttachmentsTab(); addTab( mAttachmentsTab, i18n("Config->Composer->Attachments", "A&ttachments") ); load(); } QString ComposerPage::GeneralTab::helpAnchor() const { return QString::fromLatin1("configure-composer-general"); } ComposerPageGeneralTab::ComposerPageGeneralTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QHBoxLayout *hlay; QGroupBox *group; QLabel *label; QHBox *hbox; QString msg; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // some check buttons... mAutoAppSignFileCheck = new QCheckBox( GlobalSettings::self()->autoTextSignatureItem()->label(), this ); vlay->addWidget( mAutoAppSignFileCheck ); connect( mAutoAppSignFileCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mTopQuoteCheck = new QCheckBox( GlobalSettings::self()->prependSignatureItem()->label(), this ); vlay->addWidget( mTopQuoteCheck); connect( mTopQuoteCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mSmartQuoteCheck = new QCheckBox( GlobalSettings::self()->smartQuoteItem()->label(), this, "kcfg_SmartQuote" ); QToolTip::add( mSmartQuoteCheck, i18n( "When replying, add quote signs in front of all lines of the quoted text,\n" "even when the line was created by adding an additional linebreak while\n" "word-wrapping the text." ) ); vlay->addWidget( mSmartQuoteCheck ); connect( mSmartQuoteCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mQuoteSelectionOnlyCheck = new QCheckBox( GlobalSettings::self()->quoteSelectionOnlyItem()->label(), this, "kcfg_QuoteSelectionOnly" ); QToolTip::add( mQuoteSelectionOnlyCheck, i18n( "When replying, only quote the selected text instead of the complete message " "when there is text selected in the message window." ) ); vlay->addWidget( mQuoteSelectionOnlyCheck ); connect( mQuoteSelectionOnlyCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged(void) ) ); mStripSignatureCheck = new QCheckBox( GlobalSettings::self()->stripSignatureItem()->label(), this, "kcfg_StripSignature" ); vlay->addWidget( mStripSignatureCheck ); connect( mStripSignatureCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mAutoRequestMDNCheck = new QCheckBox( GlobalSettings::self()->requestMDNItem()->label(), this, "kcfg_RequestMDN" ); vlay->addWidget( mAutoRequestMDNCheck ); connect( mAutoRequestMDNCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mShowRecentAddressesInComposer = new QCheckBox( GlobalSettings::self()->showRecentAddressesInComposerItem()->label(), this, "kcfg_ShowRecentAddressesInComposer" ); vlay->addWidget( mShowRecentAddressesInComposer ); connect( mShowRecentAddressesInComposer, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mRemoveOwnIdentitiesCheck = new QCheckBox( GlobalSettings::self()->removeOwnIdentitiesItem()->label(), this ); QToolTip::add( mRemoveOwnIdentitiesCheck, i18n( "Exclude all configured identities from Reply to All recipient list." ) ); QWhatsThis::add( mRemoveOwnIdentitiesCheck, i18n( GlobalSettings::self() ->removeOwnIdentitiesItem()->whatsThis().utf8() ) ); vlay->addWidget( mRemoveOwnIdentitiesCheck ); connect( mRemoveOwnIdentitiesCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); // a checkbox for "word wrap" and a spinbox for the column in // which to wrap: hlay = new QHBoxLayout( vlay ); // inherits spacing mWordWrapCheck = new QCheckBox( GlobalSettings::self()->wordWrapItem()->label(), this, "kcfg_WordWrap" ); hlay->addWidget( mWordWrapCheck ); connect( mWordWrapCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mWrapColumnSpin = new KIntSpinBox( 30/*min*/, 78/*max*/, 1/*step*/, 78/*init*/, 10 /*base*/, this, "kcfg_LineWrapWidth" ); mWrapColumnSpin->setEnabled( false ); // since !mWordWrapCheck->isChecked() connect( mWrapColumnSpin, SIGNAL( valueChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); hlay->addWidget( mWrapColumnSpin ); hlay->addStretch( 1 ); // only enable the spinbox if the checkbox is checked: connect( mWordWrapCheck, SIGNAL(toggled(bool)), mWrapColumnSpin, SLOT(setEnabled(bool)) ); // a checkbox for "too many recipient warning" and a spinbox for the recipient threshold hlay = new QHBoxLayout( vlay ); // inherits spacing mRecipientCheck = new QCheckBox( GlobalSettings::self()->tooManyRecipientsItem()->label(), this, "kcfg_TooManyRecipients" ); hlay->addWidget( mRecipientCheck ); connect( mRecipientCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); QString recipientCheckWhatsthis = i18n( GlobalSettings::self()->tooManyRecipientsItem()->whatsThis().utf8() ); QWhatsThis::add( mRecipientCheck, recipientCheckWhatsthis ); QToolTip::add( mRecipientCheck, i18n( "Warn if too many recipients are specified" ) ); mRecipientSpin = new KIntSpinBox( 1/*min*/, 100/*max*/, 1/*step*/, 5/*init*/, 10 /*base*/, this, "kcfg_RecipientThreshold" ); mRecipientSpin->setEnabled( false ); connect( mRecipientSpin, SIGNAL( valueChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); QString recipientWhatsthis = i18n( GlobalSettings::self()->recipientThresholdItem()->whatsThis().utf8() ); QWhatsThis::add( mRecipientSpin, recipientWhatsthis ); QToolTip::add( mRecipientSpin, i18n( "Warn if more than this many recipients are specified" ) ); hlay->addWidget( mRecipientSpin ); hlay->addStretch( 1 ); // only enable the spinbox if the checkbox is checked: connect( mRecipientCheck, SIGNAL(toggled(bool)), mRecipientSpin, SLOT(setEnabled(bool)) ); hlay = new QHBoxLayout( vlay ); // inherits spacing mAutoSave = new KIntSpinBox( 0, 60, 1, 1, 10, this, "kcfg_AutosaveInterval" ); label = new QLabel( mAutoSave, GlobalSettings::self()->autosaveIntervalItem()->label(), this ); hlay->addWidget( label ); hlay->addWidget( mAutoSave ); mAutoSave->setSpecialValueText( i18n("No autosave") ); mAutoSave->setSuffix( i18n(" min") ); hlay->addStretch( 1 ); connect( mAutoSave, SIGNAL( valueChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); hlay = new QHBoxLayout( vlay ); // inherits spacing mForwardTypeCombo = new KComboBox( false, this ); label = new QLabel( mForwardTypeCombo, i18n( "Default Forwarding Type:" ), this ); mForwardTypeCombo->insertStringList( QStringList() << i18n( "Inline" ) << i18n( "As Attachment" ) ); hlay->addWidget( label ); hlay->addWidget( mForwardTypeCombo ); hlay->addStretch( 1 ); connect( mForwardTypeCombo, SIGNAL(activated(int)), this, SLOT( slotEmitChanged( void ) ) ); hlay = new QHBoxLayout( vlay ); // inherits spacing QPushButton *completionOrderBtn = new QPushButton( i18n( "Configure Completion Order" ), this ); connect( completionOrderBtn, SIGNAL( clicked() ), this, SLOT( slotConfigureCompletionOrder() ) ); hlay->addWidget( completionOrderBtn ); hlay->addItem( new QSpacerItem(0, 0) ); // recent addresses hlay = new QHBoxLayout( vlay ); // inherits spacing QPushButton *recentAddressesBtn = new QPushButton( i18n( "Edit Recent Addresses..." ), this ); connect( recentAddressesBtn, SIGNAL( clicked() ), this, SLOT( slotConfigureRecentAddresses() ) ); hlay->addWidget( recentAddressesBtn ); hlay->addItem( new QSpacerItem(0, 0) ); // The "external editor" group: group = new QVGroupBox( i18n("External Editor"), this ); group->layout()->setSpacing( KDialog::spacingHint() ); mExternalEditorCheck = new QCheckBox( GlobalSettings::self()->useExternalEditorItem()->label(), group, "kcfg_UseExternalEditor" ); connect( mExternalEditorCheck, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged( void ) ) ); hbox = new QHBox( group ); label = new QLabel( GlobalSettings::self()->externalEditorItem()->label(), hbox ); mEditorRequester = new KURLRequester( hbox, "kcfg_ExternalEditor" ); connect( mEditorRequester, SIGNAL( urlSelected(const QString&) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mEditorRequester, SIGNAL( textChanged(const QString&) ), this, SLOT( slotEmitChanged( void ) ) ); hbox->setStretchFactor( mEditorRequester, 1 ); label->setBuddy( mEditorRequester ); label->setEnabled( false ); // since !mExternalEditorCheck->isChecked() // ### FIXME: allow only executables (x-bit when available..) mEditorRequester->setFilter( "application/x-executable " "application/x-shellscript " "application/x-desktop" ); mEditorRequester->setEnabled( false ); // !mExternalEditorCheck->isChecked() connect( mExternalEditorCheck, SIGNAL(toggled(bool)), label, SLOT(setEnabled(bool)) ); connect( mExternalEditorCheck, SIGNAL(toggled(bool)), mEditorRequester, SLOT(setEnabled(bool)) ); label = new QLabel( i18n("%f will be replaced with the " "filename to edit."), group ); label->setEnabled( false ); // see above connect( mExternalEditorCheck, SIGNAL(toggled(bool)), label, SLOT(setEnabled(bool)) ); vlay->addWidget( group ); vlay->addStretch( 100 ); } void ComposerPage::GeneralTab::doLoadFromGlobalSettings() { // various check boxes: mAutoAppSignFileCheck->setChecked( GlobalSettings::self()->autoTextSignature()=="auto" ); mTopQuoteCheck->setChecked( GlobalSettings::self()->prependSignature() ); mSmartQuoteCheck->setChecked( GlobalSettings::self()->smartQuote() ); mQuoteSelectionOnlyCheck->setChecked( GlobalSettings::self()->quoteSelectionOnly() ); mStripSignatureCheck->setChecked( GlobalSettings::self()->stripSignature() ); mAutoRequestMDNCheck->setChecked( GlobalSettings::self()->requestMDN() ); mWordWrapCheck->setChecked( GlobalSettings::self()->wordWrap() ); mWrapColumnSpin->setValue( GlobalSettings::self()->lineWrapWidth() ); mRecipientCheck->setChecked( GlobalSettings::self()->tooManyRecipients() ); mRecipientSpin->setValue( GlobalSettings::self()->recipientThreshold() ); mAutoSave->setValue( GlobalSettings::self()->autosaveInterval() ); mRemoveOwnIdentitiesCheck->setChecked( GlobalSettings::self()->removeOwnIdentities() ); if ( GlobalSettings::self()->forwardingInlineByDefault() ) mForwardTypeCombo->setCurrentItem( 0 ); else mForwardTypeCombo->setCurrentItem( 1 ); // editor group: mExternalEditorCheck->setChecked( GlobalSettings::self()->useExternalEditor() ); mEditorRequester->setURL( GlobalSettings::self()->externalEditor() ); } void ComposerPage::GeneralTab::installProfile( KConfig * profile ) { KConfigGroup composer( profile, "Composer" ); KConfigGroup general( profile, "General" ); if ( composer.hasKey( "signature" ) ) { bool state = composer.readBoolEntry("signature"); mAutoAppSignFileCheck->setChecked( state ); } if ( composer.hasKey( "prepend-signature" ) ) mTopQuoteCheck->setChecked( composer.readBoolEntry( "prepend-signature" ) ); if ( composer.hasKey( "smart-quote" ) ) mSmartQuoteCheck->setChecked( composer.readBoolEntry( "smart-quote" ) ); if ( composer.hasKey( "StripSignature" ) ) mStripSignatureCheck->setChecked( composer.readBoolEntry( "StripSignature" ) ); if ( composer.hasKey( "QuoteSelectionOnly" ) ) mQuoteSelectionOnlyCheck->setChecked( composer.readBoolEntry( "QuoteSelectionOnly" ) ); if ( composer.hasKey( "request-mdn" ) ) mAutoRequestMDNCheck->setChecked( composer.readBoolEntry( "request-mdn" ) ); if ( composer.hasKey( "word-wrap" ) ) mWordWrapCheck->setChecked( composer.readBoolEntry( "word-wrap" ) ); if ( composer.hasKey( "break-at" ) ) mWrapColumnSpin->setValue( composer.readNumEntry( "break-at" ) ); if ( composer.hasKey( "too-many-recipients" ) ) mRecipientCheck->setChecked( composer.readBoolEntry( "too-many-recipients" ) ); if ( composer.hasKey( "recipient-threshold" ) ) mRecipientSpin->setValue( composer.readNumEntry( "recipient-threshold" ) ); if ( composer.hasKey( "autosave" ) ) mAutoSave->setValue( composer.readNumEntry( "autosave" ) ); if ( composer.hasKey( "remove-own-identities-on-reply" ) ) { mRemoveOwnIdentitiesCheck->setChecked( composer.readBoolEntry("remove-own-identities-on-reply") ); } if ( general.hasKey( "use-external-editor" ) && general.hasKey( "external-editor" ) ) { mExternalEditorCheck->setChecked( general.readBoolEntry( "use-external-editor" ) ); mEditorRequester->setURL( general.readPathEntry( "external-editor" ) ); } } void ComposerPage::GeneralTab::save() { GlobalSettings::self()->setAutoTextSignature( mAutoAppSignFileCheck->isChecked() ? "auto" : "manual" ); GlobalSettings::self()->setPrependSignature( mTopQuoteCheck->isChecked()); GlobalSettings::self()->setSmartQuote( mSmartQuoteCheck->isChecked() ); GlobalSettings::self()->setQuoteSelectionOnly( mQuoteSelectionOnlyCheck->isChecked() ); GlobalSettings::self()->setStripSignature( mStripSignatureCheck->isChecked() ); GlobalSettings::self()->setRequestMDN( mAutoRequestMDNCheck->isChecked() ); GlobalSettings::self()->setWordWrap( mWordWrapCheck->isChecked() ); GlobalSettings::self()->setRemoveOwnIdentities( mRemoveOwnIdentitiesCheck->isChecked() ); GlobalSettings::self()->setLineWrapWidth( mWrapColumnSpin->value() ); GlobalSettings::self()->setTooManyRecipients( mRecipientCheck->isChecked() ); GlobalSettings::self()->setRecipientThreshold( mRecipientSpin->value() ); GlobalSettings::self()->setAutosaveInterval( mAutoSave->value() ); GlobalSettings::self()->setForwardingInlineByDefault( mForwardTypeCombo->currentItem() == 0 ); // editor group: GlobalSettings::self()->setUseExternalEditor( mExternalEditorCheck->isChecked() ); GlobalSettings::self()->setExternalEditor( mEditorRequester->url() ); } void ComposerPage::GeneralTab::slotConfigureRecentAddresses( ) { KRecentAddress::RecentAddressDialog dlg( this ); dlg.setAddresses( RecentAddresses::self( KMKernel::config() )->addresses() ); if ( dlg.exec() ) { RecentAddresses::self( KMKernel::config() )->clear(); const QStringList &addrList = dlg.addresses(); QStringList::ConstIterator it; for ( it = addrList.constBegin(); it != addrList.constEnd(); ++it ) RecentAddresses::self( KMKernel::config() )->add( *it ); } } void ComposerPage::GeneralTab::slotConfigureCompletionOrder( ) { KPIM::LdapSearch search; KPIM::CompletionOrderEditor editor( &search, this ); editor.exec(); } QString ComposerPage::PhrasesTab::helpAnchor() const { return QString::fromLatin1("configure-composer-phrases"); } ComposerPagePhrasesTab::ComposerPagePhrasesTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QGridLayout *glay; QPushButton *button; glay = new QGridLayout( this, 7, 3, KDialog::spacingHint() ); glay->setMargin( KDialog::marginHint() ); glay->setColStretch( 1, 1 ); glay->setColStretch( 2, 1 ); glay->setRowStretch( 7, 1 ); // row 0: help text glay->addMultiCellWidget( new QLabel( i18n("The following placeholders are " "supported in the reply phrases:
" "%D: date, %S: subject,
" "%e: sender's address, %F: sender's name, %f: sender's initials,
" "%T: recipient's name, %t: recipient's name and address,
" "%C: carbon copy names, %c: carbon copy names and addresses,
" "%%: percent sign, %_: space, " "%L: linebreak
"), this ), 0, 0, 0, 2 ); // row 0; cols 0..2 // row 1: label and language combo box: mPhraseLanguageCombo = new LanguageComboBox( false, this ); glay->addWidget( new QLabel( mPhraseLanguageCombo, i18n("Lang&uage:"), this ), 1, 0 ); glay->addMultiCellWidget( mPhraseLanguageCombo, 1, 1, 1, 2 ); connect( mPhraseLanguageCombo, SIGNAL(activated(const QString&)), this, SLOT(slotLanguageChanged(const QString&)) ); // row 2: "add..." and "remove" push buttons: button = new QPushButton( i18n("A&dd..."), this ); button->setAutoDefault( false ); glay->addWidget( button, 2, 1 ); mRemoveButton = new QPushButton( i18n("Re&move"), this ); mRemoveButton->setAutoDefault( false ); mRemoveButton->setEnabled( false ); // combo doesn't contain anything... glay->addWidget( mRemoveButton, 2, 2 ); connect( button, SIGNAL(clicked()), this, SLOT(slotNewLanguage()) ); connect( mRemoveButton, SIGNAL(clicked()), this, SLOT(slotRemoveLanguage()) ); // row 3: "reply to sender" line edit and label: mPhraseReplyEdit = new KLineEdit( this ); connect( mPhraseReplyEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); glay->addWidget( new QLabel( mPhraseReplyEdit, i18n("Reply to se&nder:"), this ), 3, 0 ); glay->addMultiCellWidget( mPhraseReplyEdit, 3, 3, 1, 2 ); // cols 1..2 // row 4: "reply to all" line edit and label: mPhraseReplyAllEdit = new KLineEdit( this ); connect( mPhraseReplyAllEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); glay->addWidget( new QLabel( mPhraseReplyAllEdit, i18n("Repl&y to all:"), this ), 4, 0 ); glay->addMultiCellWidget( mPhraseReplyAllEdit, 4, 4, 1, 2 ); // cols 1..2 // row 5: "forward" line edit and label: mPhraseForwardEdit = new KLineEdit( this ); connect( mPhraseForwardEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); glay->addWidget( new QLabel( mPhraseForwardEdit, i18n("&Forward:"), this ), 5, 0 ); glay->addMultiCellWidget( mPhraseForwardEdit, 5, 5, 1, 2 ); // cols 1..2 // row 6: "quote indicator" line edit and label: mPhraseIndentPrefixEdit = new KLineEdit( this ); connect( mPhraseIndentPrefixEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); glay->addWidget( new QLabel( mPhraseIndentPrefixEdit, i18n("&Quote indicator:"), this ), 6, 0 ); glay->addMultiCellWidget( mPhraseIndentPrefixEdit, 6, 6, 1, 2 ); // row 7: spacer } void ComposerPage::PhrasesTab::setLanguageItemInformation( int index ) { assert( 0 <= index && index < (int)mLanguageList.count() ); LanguageItem &l = *mLanguageList.at( index ); mPhraseReplyEdit->setText( l.mReply ); mPhraseReplyAllEdit->setText( l.mReplyAll ); mPhraseForwardEdit->setText( l.mForward ); mPhraseIndentPrefixEdit->setText( l.mIndentPrefix ); } void ComposerPage::PhrasesTab::saveActiveLanguageItem() { int index = mActiveLanguageItem; if (index == -1) return; assert( 0 <= index && index < (int)mLanguageList.count() ); LanguageItem &l = *mLanguageList.at( index ); l.mReply = mPhraseReplyEdit->text(); l.mReplyAll = mPhraseReplyAllEdit->text(); l.mForward = mPhraseForwardEdit->text(); l.mIndentPrefix = mPhraseIndentPrefixEdit->text(); } void ComposerPage::PhrasesTab::slotNewLanguage() { NewLanguageDialog dialog( mLanguageList, parentWidget(), "New", true ); if ( dialog.exec() == QDialog::Accepted ) slotAddNewLanguage( dialog.language() ); } void ComposerPage::PhrasesTab::slotAddNewLanguage( const QString& lang ) { mPhraseLanguageCombo->setCurrentItem( mPhraseLanguageCombo->insertLanguage( lang ) ); KLocale locale("kmail"); locale.setLanguage( lang ); mLanguageList.append( LanguageItem( lang, locale.translate("On %D, you wrote:"), locale.translate("On %D, %F wrote:"), locale.translate("Forwarded Message"), locale.translate(">%_") ) ); mRemoveButton->setEnabled( true ); slotLanguageChanged( QString::null ); } void ComposerPage::PhrasesTab::slotRemoveLanguage() { assert( mPhraseLanguageCombo->count() > 1 ); int index = mPhraseLanguageCombo->currentItem(); assert( 0 <= index && index < (int)mLanguageList.count() ); // remove current item from internal list and combobox: mLanguageList.remove( mLanguageList.at( index ) ); mPhraseLanguageCombo->removeItem( index ); if ( index >= (int)mLanguageList.count() ) index--; mActiveLanguageItem = index; setLanguageItemInformation( index ); mRemoveButton->setEnabled( mLanguageList.count() > 1 ); emit changed( true ); } void ComposerPage::PhrasesTab::slotLanguageChanged( const QString& ) { int index = mPhraseLanguageCombo->currentItem(); assert( index < (int)mLanguageList.count() ); saveActiveLanguageItem(); mActiveLanguageItem = index; setLanguageItemInformation( index ); emit changed( true ); } void ComposerPage::PhrasesTab::doLoadFromGlobalSettings() { mLanguageList.clear(); mPhraseLanguageCombo->clear(); mActiveLanguageItem = -1; int numLang = GlobalSettings::self()->replyLanguagesCount(); int currentNr = GlobalSettings::self()->replyCurrentLanguage(); // build mLanguageList and mPhraseLanguageCombo: for ( int i = 0 ; i < numLang ; i++ ) { ReplyPhrases replyPhrases( QString::number(i) ); replyPhrases.readConfig(); QString lang = replyPhrases.language(); mLanguageList.append( LanguageItem( lang, replyPhrases.phraseReplySender(), replyPhrases.phraseReplyAll(), replyPhrases.phraseForward(), replyPhrases.indentPrefix() ) ); mPhraseLanguageCombo->insertLanguage( lang ); } if ( currentNr >= numLang || currentNr < 0 ) currentNr = 0; if ( numLang == 0 ) { slotAddNewLanguage( KGlobal::locale()->language() ); } mPhraseLanguageCombo->setCurrentItem( currentNr ); mActiveLanguageItem = currentNr; setLanguageItemInformation( currentNr ); mRemoveButton->setEnabled( mLanguageList.count() > 1 ); } void ComposerPage::PhrasesTab::save() { GlobalSettings::self()->setReplyLanguagesCount( mLanguageList.count() ); GlobalSettings::self()->setReplyCurrentLanguage( mPhraseLanguageCombo->currentItem() ); saveActiveLanguageItem(); LanguageItemList::Iterator it = mLanguageList.begin(); for ( int i = 0 ; it != mLanguageList.end() ; ++it, ++i ) { ReplyPhrases replyPhrases( QString::number(i) ); replyPhrases.setLanguage( (*it).mLanguage ); replyPhrases.setPhraseReplySender( (*it).mReply ); replyPhrases.setPhraseReplyAll( (*it).mReplyAll ); replyPhrases.setPhraseForward( (*it).mForward ); replyPhrases.setIndentPrefix( (*it).mIndentPrefix ); replyPhrases.writeConfig(); } } QString ComposerPage::TemplatesTab::helpAnchor() const { return QString::fromLatin1("configure-composer-templates"); } ComposerPageTemplatesTab::ComposerPageTemplatesTab( QWidget * parent, const char * name ) : ConfigModuleTab ( parent, name ) { QVBoxLayout* vlay = new QVBoxLayout( this, 0, KDialog::spacingHint() ); mWidget = new TemplatesConfiguration( this ); vlay->addWidget( mWidget ); connect( mWidget, SIGNAL( changed() ), this, SLOT( slotEmitChanged( void ) ) ); } void ComposerPage::TemplatesTab::doLoadFromGlobalSettings() { mWidget->loadFromGlobal(); } void ComposerPage::TemplatesTab::save() { mWidget->saveToGlobal(); } QString ComposerPage::CustomTemplatesTab::helpAnchor() const { return QString::fromLatin1("configure-composer-custom-templates"); } ComposerPageCustomTemplatesTab::ComposerPageCustomTemplatesTab( QWidget * parent, const char * name ) : ConfigModuleTab ( parent, name ) { QVBoxLayout* vlay = new QVBoxLayout( this, 0, KDialog::spacingHint() ); mWidget = new CustomTemplates( this ); vlay->addWidget( mWidget ); connect( mWidget, SIGNAL( changed() ), this, SLOT( slotEmitChanged( void ) ) ); } void ComposerPage::CustomTemplatesTab::doLoadFromGlobalSettings() { mWidget->load(); } void ComposerPage::CustomTemplatesTab::save() { mWidget->save(); } QString ComposerPage::SubjectTab::helpAnchor() const { return QString::fromLatin1("configure-composer-subject"); } ComposerPageSubjectTab::ComposerPageSubjectTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QGroupBox *group; QLabel *label; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); group = new QVGroupBox( i18n("Repl&y Subject Prefixes"), this ); group->layout()->setSpacing( KDialog::spacingHint() ); // row 0: help text: label = new QLabel( i18n("Recognize any sequence of the following prefixes\n" "(entries are case-insensitive regular expressions):"), group ); label->setAlignment( AlignLeft|WordBreak ); // row 1, string list editor: SimpleStringListEditor::ButtonCode buttonCode = static_cast( SimpleStringListEditor::Add | SimpleStringListEditor::Remove | SimpleStringListEditor::Modify ); mReplyListEditor = new SimpleStringListEditor( group, 0, buttonCode, i18n("A&dd..."), i18n("Re&move"), i18n("Mod&ify..."), i18n("Enter new reply prefix:") ); connect( mReplyListEditor, SIGNAL( changed( void ) ), this, SLOT( slotEmitChanged( void ) ) ); // row 2: "replace [...]" check box: mReplaceReplyPrefixCheck = new QCheckBox( GlobalSettings::self()->replaceReplyPrefixItem()->label(), group, "kcfg_ReplaceReplyPrefix" ); connect( mReplaceReplyPrefixCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( group ); group = new QVGroupBox( i18n("For&ward Subject Prefixes"), this ); group->layout()->setSpacing( KDialog::marginHint() ); // row 0: help text: label= new QLabel( i18n("Recognize any sequence of the following prefixes\n" "(entries are case-insensitive regular expressions):"), group ); label->setAlignment( AlignLeft|WordBreak ); // row 1: string list editor mForwardListEditor = new SimpleStringListEditor( group, 0, buttonCode, i18n("Add..."), i18n("Remo&ve"), i18n("Modify..."), i18n("Enter new forward prefix:") ); connect( mForwardListEditor, SIGNAL( changed( void ) ), this, SLOT( slotEmitChanged( void ) ) ); // row 3: "replace [...]" check box: mReplaceForwardPrefixCheck = new QCheckBox( GlobalSettings::self()->replaceForwardPrefixItem()->label(), group, "kcfg_ReplaceForwardPrefix" ); connect( mReplaceForwardPrefixCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( group ); } void ComposerPage::SubjectTab::doLoadFromGlobalSettings() { mReplyListEditor->setStringList( GlobalSettings::self()->replyPrefixes() ); mReplaceReplyPrefixCheck->setChecked( GlobalSettings::self()->replaceReplyPrefix() ); mForwardListEditor->setStringList( GlobalSettings::self()->forwardPrefixes() ); mReplaceForwardPrefixCheck->setChecked( GlobalSettings::self()->replaceForwardPrefix() ); } void ComposerPage::SubjectTab::save() { GlobalSettings::self()->setReplyPrefixes( mReplyListEditor->stringList() ); GlobalSettings::self()->setForwardPrefixes( mForwardListEditor->stringList() ); } QString ComposerPage::CharsetTab::helpAnchor() const { return QString::fromLatin1("configure-composer-charset"); } ComposerPageCharsetTab::ComposerPageCharsetTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QLabel *label; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); label = new QLabel( i18n("This list is checked for every outgoing message " "from the top to the bottom for a charset that " "contains all required characters."), this ); label->setAlignment( WordBreak); vlay->addWidget( label ); mCharsetListEditor = new SimpleStringListEditor( this, 0, SimpleStringListEditor::All, i18n("A&dd..."), i18n("Remo&ve"), i18n("&Modify..."), i18n("Enter charset:") ); connect( mCharsetListEditor, SIGNAL( changed( void ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mCharsetListEditor, 1 ); mKeepReplyCharsetCheck = new QCheckBox( i18n("&Keep original charset when " "replying or forwarding (if " "possible)"), this ); connect( mKeepReplyCharsetCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mKeepReplyCharsetCheck ); connect( mCharsetListEditor, SIGNAL(aboutToAdd(QString&)), this, SLOT(slotVerifyCharset(QString&)) ); } void ComposerPage::CharsetTab::slotVerifyCharset( QString & charset ) { if ( charset.isEmpty() ) return; // KCharsets::codecForName("us-ascii") returns "iso-8859-1" (cf. Bug #49812) // therefore we have to treat this case specially if ( charset.lower() == QString::fromLatin1("us-ascii") ) { charset = QString::fromLatin1("us-ascii"); return; } if ( charset.lower() == QString::fromLatin1("locale") ) { charset = QString::fromLatin1("%1 (locale)") .arg( QCString( kmkernel->networkCodec()->mimeName() ).lower() ); return; } bool ok = false; QTextCodec *codec = KGlobal::charsets()->codecForName( charset, ok ); if ( ok && codec ) { charset = QString::fromLatin1( codec->mimeName() ).lower(); return; } KMessageBox::sorry( this, i18n("This charset is not supported.") ); charset = QString::null; } void ComposerPage::CharsetTab::doLoadOther() { KConfigGroup composer( KMKernel::config(), "Composer" ); QStringList charsets = composer.readListEntry( "pref-charsets" ); for ( QStringList::Iterator it = charsets.begin() ; it != charsets.end() ; ++it ) if ( (*it) == QString::fromLatin1("locale") ) { QCString cset = kmkernel->networkCodec()->mimeName(); KPIM::kAsciiToLower( cset.data() ); (*it) = QString("%1 (locale)").arg( cset ); } mCharsetListEditor->setStringList( charsets ); mKeepReplyCharsetCheck->setChecked( !composer.readBoolEntry( "force-reply-charset", false ) ); } void ComposerPage::CharsetTab::save() { KConfigGroup composer( KMKernel::config(), "Composer" ); QStringList charsetList = mCharsetListEditor->stringList(); QStringList::Iterator it = charsetList.begin(); for ( ; it != charsetList.end() ; ++it ) if ( (*it).endsWith("(locale)") ) (*it) = "locale"; composer.writeEntry( "pref-charsets", charsetList ); composer.writeEntry( "force-reply-charset", !mKeepReplyCharsetCheck->isChecked() ); } QString ComposerPage::HeadersTab::helpAnchor() const { return QString::fromLatin1("configure-composer-headers"); } ComposerPageHeadersTab::ComposerPageHeadersTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QHBoxLayout *hlay; QGridLayout *glay; QLabel *label; QPushButton *button; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "Use custom Message-Id suffix" checkbox: mCreateOwnMessageIdCheck = new QCheckBox( i18n("&Use custom message-id suffix"), this ); connect( mCreateOwnMessageIdCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mCreateOwnMessageIdCheck ); // "Message-Id suffix" line edit and label: hlay = new QHBoxLayout( vlay ); // inherits spacing mMessageIdSuffixEdit = new KLineEdit( this ); // only ASCII letters, digits, plus, minus and dots are allowed mMessageIdSuffixValidator = new QRegExpValidator( QRegExp( "[a-zA-Z0-9+-]+(?:\\.[a-zA-Z0-9+-]+)*" ), this ); mMessageIdSuffixEdit->setValidator( mMessageIdSuffixValidator ); label = new QLabel( mMessageIdSuffixEdit, i18n("Custom message-&id suffix:"), this ); label->setEnabled( false ); // since !mCreateOwnMessageIdCheck->isChecked() mMessageIdSuffixEdit->setEnabled( false ); hlay->addWidget( label ); hlay->addWidget( mMessageIdSuffixEdit, 1 ); connect( mCreateOwnMessageIdCheck, SIGNAL(toggled(bool) ), label, SLOT(setEnabled(bool)) ); connect( mCreateOwnMessageIdCheck, SIGNAL(toggled(bool) ), mMessageIdSuffixEdit, SLOT(setEnabled(bool)) ); connect( mMessageIdSuffixEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); // horizontal rule and "custom header fields" label: vlay->addWidget( new KSeparator( KSeparator::HLine, this ) ); vlay->addWidget( new QLabel( i18n("Define custom mime header fields:"), this) ); // "custom header fields" listbox: glay = new QGridLayout( vlay, 5, 3 ); // inherits spacing glay->setRowStretch( 2, 1 ); glay->setColStretch( 1, 1 ); mTagList = new ListView( this, "tagList" ); mTagList->addColumn( i18n("Name") ); mTagList->addColumn( i18n("Value") ); mTagList->setAllColumnsShowFocus( true ); mTagList->setSorting( -1 ); connect( mTagList, SIGNAL(selectionChanged()), this, SLOT(slotMimeHeaderSelectionChanged()) ); glay->addMultiCellWidget( mTagList, 0, 2, 0, 1 ); // "new" and "remove" buttons: button = new QPushButton( i18n("Ne&w"), this ); connect( button, SIGNAL(clicked()), this, SLOT(slotNewMimeHeader()) ); button->setAutoDefault( false ); glay->addWidget( button, 0, 2 ); mRemoveHeaderButton = new QPushButton( i18n("Re&move"), this ); connect( mRemoveHeaderButton, SIGNAL(clicked()), this, SLOT(slotRemoveMimeHeader()) ); button->setAutoDefault( false ); glay->addWidget( mRemoveHeaderButton, 1, 2 ); // "name" and "value" line edits and labels: mTagNameEdit = new KLineEdit( this ); mTagNameEdit->setEnabled( false ); mTagNameLabel = new QLabel( mTagNameEdit, i18n("&Name:"), this ); mTagNameLabel->setEnabled( false ); glay->addWidget( mTagNameLabel, 3, 0 ); glay->addWidget( mTagNameEdit, 3, 1 ); connect( mTagNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotMimeHeaderNameChanged(const QString&)) ); mTagValueEdit = new KLineEdit( this ); mTagValueEdit->setEnabled( false ); mTagValueLabel = new QLabel( mTagValueEdit, i18n("&Value:"), this ); mTagValueLabel->setEnabled( false ); glay->addWidget( mTagValueLabel, 4, 0 ); glay->addWidget( mTagValueEdit, 4, 1 ); connect( mTagValueEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotMimeHeaderValueChanged(const QString&)) ); } void ComposerPage::HeadersTab::slotMimeHeaderSelectionChanged() { QListViewItem * item = mTagList->selectedItem(); if ( item ) { mTagNameEdit->setText( item->text( 0 ) ); mTagValueEdit->setText( item->text( 1 ) ); } else { mTagNameEdit->clear(); mTagValueEdit->clear(); } mRemoveHeaderButton->setEnabled( item ); mTagNameEdit->setEnabled( item ); mTagValueEdit->setEnabled( item ); mTagNameLabel->setEnabled( item ); mTagValueLabel->setEnabled( item ); } void ComposerPage::HeadersTab::slotMimeHeaderNameChanged( const QString & text ) { // is called on ::setup(), when clearing the line edits. So be // prepared to not find a selection: QListViewItem * item = mTagList->selectedItem(); if ( item ) item->setText( 0, text ); emit changed( true ); } void ComposerPage::HeadersTab::slotMimeHeaderValueChanged( const QString & text ) { // is called on ::setup(), when clearing the line edits. So be // prepared to not find a selection: QListViewItem * item = mTagList->selectedItem(); if ( item ) item->setText( 1, text ); emit changed( true ); } void ComposerPage::HeadersTab::slotNewMimeHeader() { QListViewItem *listItem = new QListViewItem( mTagList ); mTagList->setCurrentItem( listItem ); mTagList->setSelected( listItem, true ); emit changed( true ); } void ComposerPage::HeadersTab::slotRemoveMimeHeader() { // calling this w/o selection is a programming error: QListViewItem * item = mTagList->selectedItem(); if ( !item ) { kdDebug(5006) << "==================================================\n" << "Error: Remove button was pressed although no custom header was selected\n" << "==================================================\n"; return; } QListViewItem * below = item->nextSibling(); delete item; if ( below ) mTagList->setSelected( below, true ); else if ( mTagList->lastItem() ) mTagList->setSelected( mTagList->lastItem(), true ); emit changed( true ); } void ComposerPage::HeadersTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General" ); QString suffix = general.readEntry( "myMessageIdSuffix" ); mMessageIdSuffixEdit->setText( suffix ); bool state = ( !suffix.isEmpty() && general.readBoolEntry( "useCustomMessageIdSuffix", false ) ); mCreateOwnMessageIdCheck->setChecked( state ); mTagList->clear(); mTagNameEdit->clear(); mTagValueEdit->clear(); QListViewItem * item = 0; int count = general.readNumEntry( "mime-header-count", 0 ); for( int i = 0 ; i < count ; i++ ) { KConfigGroup config( KMKernel::config(), QCString("Mime #") + QCString().setNum(i) ); QString name = config.readEntry( "name" ); QString value = config.readEntry( "value" ); if( !name.isEmpty() ) item = new QListViewItem( mTagList, item, name, value ); } if ( mTagList->childCount() ) { mTagList->setCurrentItem( mTagList->firstChild() ); mTagList->setSelected( mTagList->firstChild(), true ); } else { // disable the "Remove" button mRemoveHeaderButton->setEnabled( false ); } } void ComposerPage::HeadersTab::save() { KConfigGroup general( KMKernel::config(), "General" ); general.writeEntry( "useCustomMessageIdSuffix", mCreateOwnMessageIdCheck->isChecked() ); general.writeEntry( "myMessageIdSuffix", mMessageIdSuffixEdit->text() ); int numValidEntries = 0; QListViewItem * item = mTagList->firstChild(); for ( ; item ; item = item->itemBelow() ) if( !item->text(0).isEmpty() ) { KConfigGroup config( KMKernel::config(), QCString("Mime #") + QCString().setNum( numValidEntries ) ); config.writeEntry( "name", item->text( 0 ) ); config.writeEntry( "value", item->text( 1 ) ); numValidEntries++; } general.writeEntry( "mime-header-count", numValidEntries ); } QString ComposerPage::AttachmentsTab::helpAnchor() const { return QString::fromLatin1("configure-composer-attachments"); } ComposerPageAttachmentsTab::ComposerPageAttachmentsTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QLabel *label; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "Outlook compatible attachment naming" check box mOutlookCompatibleCheck = new QCheckBox( i18n( "Outlook-compatible attachment naming" ), this ); mOutlookCompatibleCheck->setChecked( false ); QToolTip::add( mOutlookCompatibleCheck, i18n( "Turn this option on to make Outlook(tm) understand attachment names " "containing non-English characters" ) ); connect( mOutlookCompatibleCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mOutlookCompatibleCheck, SIGNAL( clicked() ), this, SLOT( slotOutlookCompatibleClicked() ) ); vlay->addWidget( mOutlookCompatibleCheck ); vlay->addSpacing( 5 ); // "Enable detection of missing attachments" check box mMissingAttachmentDetectionCheck = new QCheckBox( i18n("E&nable detection of missing attachments"), this ); mMissingAttachmentDetectionCheck->setChecked( true ); connect( mMissingAttachmentDetectionCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mMissingAttachmentDetectionCheck ); // "Attachment key words" label and string list editor label = new QLabel( i18n("Recognize any of the following key words as " "intention to attach a file:"), this ); label->setAlignment( AlignLeft|WordBreak ); vlay->addWidget( label ); SimpleStringListEditor::ButtonCode buttonCode = static_cast( SimpleStringListEditor::Add | SimpleStringListEditor::Remove | SimpleStringListEditor::Modify ); mAttachWordsListEditor = new SimpleStringListEditor( this, 0, buttonCode, i18n("A&dd..."), i18n("Re&move"), i18n("Mod&ify..."), i18n("Enter new key word:") ); connect( mAttachWordsListEditor, SIGNAL( changed( void ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mAttachWordsListEditor ); connect( mMissingAttachmentDetectionCheck, SIGNAL(toggled(bool) ), label, SLOT(setEnabled(bool)) ); connect( mMissingAttachmentDetectionCheck, SIGNAL(toggled(bool) ), mAttachWordsListEditor, SLOT(setEnabled(bool)) ); } void ComposerPage::AttachmentsTab::doLoadFromGlobalSettings() { mOutlookCompatibleCheck->setChecked( GlobalSettings::self()->outlookCompatibleAttachments() ); mMissingAttachmentDetectionCheck->setChecked( GlobalSettings::self()->showForgottenAttachmentWarning() ); QStringList attachWordsList = GlobalSettings::self()->attachmentKeywords(); if ( attachWordsList.isEmpty() ) { // default value attachWordsList << QString::fromLatin1("attachment") << QString::fromLatin1("attached"); if ( QString::fromLatin1("attachment") != i18n("attachment") ) attachWordsList << i18n("attachment"); if ( QString::fromLatin1("attached") != i18n("attached") ) attachWordsList << i18n("attached"); } mAttachWordsListEditor->setStringList( attachWordsList ); } void ComposerPage::AttachmentsTab::save() { GlobalSettings::self()->setOutlookCompatibleAttachments( mOutlookCompatibleCheck->isChecked() ); GlobalSettings::self()->setShowForgottenAttachmentWarning( mMissingAttachmentDetectionCheck->isChecked() ); GlobalSettings::self()->setAttachmentKeywords( mAttachWordsListEditor->stringList() ); } void ComposerPageAttachmentsTab::slotOutlookCompatibleClicked() { if (mOutlookCompatibleCheck->isChecked()) { KMessageBox::information(0,i18n("You have chosen to " "encode attachment names containing non-English characters in a way that " "is understood by Outlook(tm) and other mail clients that do not " "support standard-compliant encoded attachment names.\n" "Note that KMail may create non-standard compliant messages, " "and consequently it is possible that your messages will not be " "understood by standard-compliant mail clients; so, unless you have no " "other choice, you should not enable this option." ) ); } } // ************************************************************* // * * // * SecurityPage * // * * // ************************************************************* QString SecurityPage::helpAnchor() const { return QString::fromLatin1("configure-security"); } SecurityPage::SecurityPage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { // // "Reading" tab: // mGeneralTab = new GeneralTab(); // @TODO: rename addTab( mGeneralTab, i18n("&Reading") ); // // "Composing" tab: // mComposerCryptoTab = new ComposerCryptoTab(); addTab( mComposerCryptoTab, i18n("Composing") ); // // "Warnings" tab: // mWarningTab = new WarningTab(); addTab( mWarningTab, i18n("Warnings") ); // // "S/MIME Validation" tab: // mSMimeTab = new SMimeTab(); addTab( mSMimeTab, i18n("S/MIME &Validation") ); // // "Crypto Backends" tab: // mCryptPlugTab = new CryptPlugTab(); addTab( mCryptPlugTab, i18n("Crypto Backe&nds") ); load(); } void SecurityPage::installProfile( KConfig * profile ) { mGeneralTab->installProfile( profile ); mComposerCryptoTab->installProfile( profile ); mWarningTab->installProfile( profile ); mSMimeTab->installProfile( profile ); } QString SecurityPage::GeneralTab::helpAnchor() const { return QString::fromLatin1("configure-security-reading"); } SecurityPageGeneralTab::SecurityPageGeneralTab( QWidget * parent, const char * name ) : ConfigModuleTab ( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QHBox *hbox; QGroupBox *group; QRadioButton *radio; KActiveLabel *label; QWidget *w; QString msg; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // QWhat'sThis texts QString htmlWhatsThis = i18n( "

Messages sometimes come in both formats. " "This option controls whether you want the HTML part or the plain " "text part to be displayed.

" "

Displaying the HTML part makes the message look better, " "but at the same time increases the risk of security holes " "being exploited.

" "

Displaying the plain text part loses much of the message's " "formatting, but makes it almost impossible " "to exploit security holes in the HTML renderer (Konqueror).

" "

The option below guards against one common misuse of HTML " "messages, but it cannot guard against security issues that were " "not known at the time this version of KMail was written.

" "

It is therefore advisable to not prefer HTML to " "plain text.

" "

You can still prefer plain text mails in general but get " "a hint that there is a HTML representation available which you " "can activate on demand.

" "

Note: You can set this option on a per-folder basis " "from the Folder menu of KMail's main window.

" ); QString externalWhatsThis = i18n( "

Some mail advertisements are in HTML " "and contain references to, for example, images that the advertisers" " employ to find out that you have read their message " "("web bugs").

" "

There is no valid reason to load images off the Internet like " "this, since the sender can always attach the required images " "directly to the message.

" "

To guard from such a misuse of the HTML displaying feature " "of KMail, this option is disabled by default.

" "

However, if you wish to, for example, view images in HTML " "messages that were not attached to it, you can enable this " "option, but you should be aware of the possible problem.

" ); QString receiptWhatsThis = i18n( "

Message Disposition " "Notification Policy

" "

MDNs are a generalization of what is commonly called read " "receipt. The message author requests a disposition " "notification to be sent and the receiver's mail program " "generates a reply from which the author can learn what " "happened to his message. Common disposition types include " "displayed (i.e. read), deleted and dispatched " "(e.g. forwarded).

" "

The following options are available to control KMail's " "sending of MDNs:

" "
    " "
  • Ignore: Ignores any request for disposition " "notifications. No MDN will ever be sent automatically " "(recommended).
  • " "
  • Ask: Answers requests only after asking the user " "for permission. This way, you can send MDNs for selected " "messages while denying or ignoring them for others.
  • " "
  • Deny: Always sends a denied notification. This " "is only slightly better than always sending MDNs. " "The author will still know that the messages has been acted " "upon, he just cannot tell whether it was deleted or read etc.
  • " "
  • Always send: Always sends the requested " "disposition notification. That means that the author of the " "message gets to know when the message was acted upon and, " "in addition, what happened to it (displayed, deleted, " "etc.). This option is strongly discouraged, but since it " "makes much sense e.g. for customer relationship management, " "it has been made available.
  • " "
" ); // "HTML Messages" group box: group = new QVGroupBox( i18n( "HTML Messages" ), this ); group->layout()->setSpacing( KDialog::spacingHint() ); QButtonGroup *rg = new QButtonGroup( group ); rg->hide(); mPlainMailRB = new QRadioButton( i18n("Prefer &plain text to HTML" ), group ); rg->insert( mPlainMailRB ); QWhatsThis::add( mPlainMailRB, htmlWhatsThis ); connect( mPlainMailRB, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mHtmlMailRB = new QRadioButton( i18n("Prefer H&TML to plain text"), group ); rg->insert( mHtmlMailRB ); QWhatsThis::add( mHtmlMailRB, htmlWhatsThis ); connect( mHtmlMailRB, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mPlainWithOptionRB = new QRadioButton( i18n("Prefer &plain text and show hint to HTML version if available." ), group ); rg->insert( mPlainWithOptionRB ); QWhatsThis::add( mPlainMailRB, htmlWhatsThis ); connect( mPlainWithOptionRB, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mExternalReferences = new QCheckBox( i18n("Allow messages to load e&xternal " "references from the Internet" ), group ); QWhatsThis::add( mExternalReferences, externalWhatsThis ); connect( mExternalReferences, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); label = new KActiveLabel( i18n("WARNING: Allowing HTML in email may " "increase the risk that your system will be " "compromised by present and anticipated security " "exploits. More about " "HTML mails... More " "about external references...") .arg(htmlWhatsThis).arg(externalWhatsThis), group ); vlay->addWidget( group ); // encrypted messages group group = new QVGroupBox( i18n("Encrypted Messages"), this ); group->layout()->setSpacing( KDialog::spacingHint() ); mAlwaysDecrypt = new QCheckBox( i18n( "Attempt decryption of encrypted messages when viewing" ), group ); connect( mAlwaysDecrypt, SIGNAL(stateChanged(int)), this, SLOT(slotEmitChanged()) ); vlay->addWidget( group ); // "Message Disposition Notification" groupbox: group = new QVGroupBox( i18n("Message Disposition Notifications"), this ); group->layout()->setSpacing( KDialog::spacingHint() ); // "ignore", "ask", "deny", "always send" radiobutton line: mMDNGroup = new QButtonGroup( group ); mMDNGroup->hide(); connect( mMDNGroup, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); hbox = new QHBox( group ); hbox->setSpacing( KDialog::spacingHint() ); (void)new QLabel( i18n("Send policy:"), hbox ); radio = new QRadioButton( i18n("&Ignore"), hbox ); mMDNGroup->insert( radio ); radio = new QRadioButton( i18n("As&k"), hbox ); mMDNGroup->insert( radio ); radio = new QRadioButton( i18n("&Deny"), hbox ); mMDNGroup->insert( radio ); radio = new QRadioButton( i18n("Al&ways send"), hbox ); mMDNGroup->insert( radio ); for ( int i = 0 ; i < mMDNGroup->count() ; ++i ) QWhatsThis::add( mMDNGroup->find( i ), receiptWhatsThis ); w = new QWidget( hbox ); // spacer hbox->setStretchFactor( w, 1 ); // "Original Message quote" radiobutton line: mOrigQuoteGroup = new QButtonGroup( group ); mOrigQuoteGroup->hide(); connect( mOrigQuoteGroup, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); hbox = new QHBox( group ); hbox->setSpacing( KDialog::spacingHint() ); (void)new QLabel( i18n("Quote original message:"), hbox ); radio = new QRadioButton( i18n("Nothin&g"), hbox ); mOrigQuoteGroup->insert( radio ); radio = new QRadioButton( i18n("&Full message"), hbox ); mOrigQuoteGroup->insert( radio ); radio = new QRadioButton( i18n("Onl&y headers"), hbox ); mOrigQuoteGroup->insert( radio ); w = new QWidget( hbox ); hbox->setStretchFactor( w, 1 ); mNoMDNsWhenEncryptedCheck = new QCheckBox( i18n("Do not send MDNs in response to encrypted messages"), group ); connect( mNoMDNsWhenEncryptedCheck, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); // Warning label: label = new KActiveLabel( i18n("WARNING: Unconditionally returning " "confirmations undermines your privacy. " "More...") .arg(receiptWhatsThis), group ); vlay->addWidget( group ); // "Attached keys" group box: group = new QVGroupBox( i18n( "Certificate && Key Bundle Attachments" ), this ); group->layout()->setSpacing( KDialog::spacingHint() ); mAutomaticallyImportAttachedKeysCheck = new QCheckBox( i18n("Automatically import keys and certificates"), group ); connect( mAutomaticallyImportAttachedKeysCheck, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); + mAutomaticallySearchForEncryptionKeys = new QCheckBox( i18n("Automatically search for encryption keys"), group ); + connect( mAutomaticallySearchForEncryptionKeys, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); + vlay->addWidget( group ); vlay->addStretch( 10 ); // spacer } void SecurityPage::GeneralTab::doLoadOther() { const KConfigGroup reader( KMKernel::config(), "Reader" ); /* For historical reasons this is implemented as bool options as the htmlMail * option was there first. */ mPlainMailRB->setChecked( reader.readBoolEntry( "plainMail", true ) ); mPlainWithOptionRB->setChecked( reader.readBoolEntry( "plainWithOption", false ) ); mHtmlMailRB->setChecked( reader.readBoolEntry( "htmlMail", false ) ); mExternalReferences->setChecked( reader.readBoolEntry( "htmlLoadExternal", false ) ); mAutomaticallyImportAttachedKeysCheck->setChecked( reader.readBoolEntry( "AutoImportKeys", false ) ); + mAutomaticallySearchForEncryptionKeys->setChecked( reader.readBoolEntry( "LocateKeys", true ) ); mAlwaysDecrypt->setChecked( GlobalSettings::self()->alwaysDecrypt() ); const KConfigGroup mdn( KMKernel::config(), "MDN" ); int num = mdn.readNumEntry( "default-policy", 0 ); if ( num < 0 || num >= mMDNGroup->count() ) num = 0; mMDNGroup->setButton( num ); num = mdn.readNumEntry( "quote-message", 0 ); if ( num < 0 || num >= mOrigQuoteGroup->count() ) num = 0; mOrigQuoteGroup->setButton( num ); mNoMDNsWhenEncryptedCheck->setChecked(mdn.readBoolEntry( "not-send-when-encrypted", true )); } void SecurityPage::GeneralTab::installProfile( KConfig * profile ) { const KConfigGroup reader( profile, "Reader" ); const KConfigGroup mdn( profile, "MDN" ); mPlainMailRB->setChecked( reader.readBoolEntry( "plainMail", true ) ); mPlainWithOptionRB->setChecked( reader.readBoolEntry( "plainWithOption", false ) ); if ( reader.hasKey( "htmlMail" ) ) mHtmlMailRB->setChecked( reader.readBoolEntry( "htmlMail" ) ); if ( reader.hasKey( "htmlLoadExternal" ) ) mExternalReferences->setChecked( reader.readBoolEntry( "htmlLoadExternal" ) ); if ( reader.hasKey( "AutoImportKeys" ) ) mAutomaticallyImportAttachedKeysCheck->setChecked( reader.readBoolEntry( "AutoImportKeys" ) ); + if ( reader.hasKey( "LocateKeys" ) ) + mAutomaticallySearchForEncryptionKeys->setChecked( reader.readBoolEntry( "LocateKeys" ) ); if ( mdn.hasKey( "default-policy" ) ) { int num = mdn.readNumEntry( "default-policy" ); if ( num < 0 || num >= mMDNGroup->count() ) num = 0; mMDNGroup->setButton( num ); } if ( mdn.hasKey( "quote-message" ) ) { int num = mdn.readNumEntry( "quote-message" ); if ( num < 0 || num >= mOrigQuoteGroup->count() ) num = 0; mOrigQuoteGroup->setButton( num ); } if ( mdn.hasKey( "not-send-when-encrypted" ) ) mNoMDNsWhenEncryptedCheck->setChecked(mdn.readBoolEntry( "not-send-when-encrypted" )); } void SecurityPage::GeneralTab::save() { KConfigGroup reader( KMKernel::config(), "Reader" ); KConfigGroup mdn( KMKernel::config(), "MDN" ); if (reader.readBoolEntry( "htmlMail", false ) != mHtmlMailRB->isChecked()) { if (KMessageBox::warningContinueCancel(this, i18n("Changing the global " "HTML setting will override all folder specific values."), QString::null, KStdGuiItem::cont(), "htmlMailOverride") == KMessageBox::Continue) { reader.writeEntry( "htmlMail", mHtmlMailRB->isChecked() ); reader.writeEntry( "plainMail", mPlainMailRB->isChecked() ); reader.writeEntry( "plainWithOption", mPlainWithOptionRB->isChecked() ); QStringList names; QValueList > folders; kmkernel->folderMgr()->createFolderList(&names, &folders); kmkernel->imapFolderMgr()->createFolderList(&names, &folders); kmkernel->dimapFolderMgr()->createFolderList(&names, &folders); kmkernel->searchFolderMgr()->createFolderList(&names, &folders); for (QValueList >::iterator it = folders.begin(); it != folders.end(); ++it) { if (*it) { KConfigGroupSaver saver(KMKernel::config(), "Folder-" + (*it)->idString()); KMKernel::config()->writeEntry("htmlMailOverride", false); } } } } reader.writeEntry( "htmlLoadExternal", mExternalReferences->isChecked() ); reader.writeEntry( "AutoImportKeys", mAutomaticallyImportAttachedKeysCheck->isChecked() ); + reader.writeEntry( "LocateKeys", mAutomaticallySearchForEncryptionKeys->isChecked() ); mdn.writeEntry( "default-policy", mMDNGroup->id( mMDNGroup->selected() ) ); mdn.writeEntry( "quote-message", mOrigQuoteGroup->id( mOrigQuoteGroup->selected() ) ); mdn.writeEntry( "not-send-when-encrypted", mNoMDNsWhenEncryptedCheck->isChecked() ); GlobalSettings::self()->setAlwaysDecrypt( mAlwaysDecrypt->isChecked() ); } QString SecurityPage::ComposerCryptoTab::helpAnchor() const { return QString::fromLatin1("configure-security-composing"); } SecurityPageComposerCryptoTab::SecurityPageComposerCryptoTab( QWidget * parent, const char * name ) : ConfigModuleTab ( parent, name ) { // the margins are inside mWidget itself QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 ); mWidget = new ComposerCryptoConfiguration( this ); connect( mWidget->mAutoSignature, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mEncToSelf, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mShowEncryptionResult, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mShowKeyApprovalDlg, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mAutoEncrypt, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mNeverEncryptWhenSavingInDrafts, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mStoreEncrypted, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); vlay->addWidget( mWidget ); } void SecurityPage::ComposerCryptoTab::doLoadOther() { const KConfigGroup composer( KMKernel::config(), "Composer" ); // If you change default values, sync messagecomposer.cpp too mWidget->mAutoSignature->setChecked( composer.readBoolEntry( "pgp-auto-sign", false ) ); mWidget->mEncToSelf->setChecked( composer.readBoolEntry( "crypto-encrypt-to-self", true ) ); mWidget->mShowEncryptionResult->setChecked( false ); //composer.readBoolEntry( "crypto-show-encryption-result", true ) ); mWidget->mShowEncryptionResult->hide(); mWidget->mShowKeyApprovalDlg->setChecked( composer.readBoolEntry( "crypto-show-keys-for-approval", true ) ); mWidget->mAutoEncrypt->setChecked( composer.readBoolEntry( "pgp-auto-encrypt", false ) ); mWidget->mNeverEncryptWhenSavingInDrafts->setChecked( composer.readBoolEntry( "never-encrypt-drafts", true ) ); mWidget->mStoreEncrypted->setChecked( composer.readBoolEntry( "crypto-store-encrypted", true ) ); } void SecurityPage::ComposerCryptoTab::installProfile( KConfig * profile ) { const KConfigGroup composer( profile, "Composer" ); if ( composer.hasKey( "pgp-auto-sign" ) ) mWidget->mAutoSignature->setChecked( composer.readBoolEntry( "pgp-auto-sign" ) ); if ( composer.hasKey( "crypto-encrypt-to-self" ) ) mWidget->mEncToSelf->setChecked( composer.readBoolEntry( "crypto-encrypt-to-self" ) ); if ( composer.hasKey( "crypto-show-encryption-result" ) ) mWidget->mShowEncryptionResult->setChecked( composer.readBoolEntry( "crypto-show-encryption-result" ) ); if ( composer.hasKey( "crypto-show-keys-for-approval" ) ) mWidget->mShowKeyApprovalDlg->setChecked( composer.readBoolEntry( "crypto-show-keys-for-approval" ) ); if ( composer.hasKey( "pgp-auto-encrypt" ) ) mWidget->mAutoEncrypt->setChecked( composer.readBoolEntry( "pgp-auto-encrypt" ) ); if ( composer.hasKey( "never-encrypt-drafts" ) ) mWidget->mNeverEncryptWhenSavingInDrafts->setChecked( composer.readBoolEntry( "never-encrypt-drafts" ) ); if ( composer.hasKey( "crypto-store-encrypted" ) ) mWidget->mStoreEncrypted->setChecked( composer.readBoolEntry( "crypto-store-encrypted" ) ); } void SecurityPage::ComposerCryptoTab::save() { KConfigGroup composer( KMKernel::config(), "Composer" ); composer.writeEntry( "pgp-auto-sign", mWidget->mAutoSignature->isChecked() ); composer.writeEntry( "crypto-encrypt-to-self", mWidget->mEncToSelf->isChecked() ); composer.writeEntry( "crypto-show-encryption-result", mWidget->mShowEncryptionResult->isChecked() ); composer.writeEntry( "crypto-show-keys-for-approval", mWidget->mShowKeyApprovalDlg->isChecked() ); composer.writeEntry( "pgp-auto-encrypt", mWidget->mAutoEncrypt->isChecked() ); composer.writeEntry( "never-encrypt-drafts", mWidget->mNeverEncryptWhenSavingInDrafts->isChecked() ); composer.writeEntry( "crypto-store-encrypted", mWidget->mStoreEncrypted->isChecked() ); } QString SecurityPage::WarningTab::helpAnchor() const { return QString::fromLatin1("configure-security-warnings"); } SecurityPageWarningTab::SecurityPageWarningTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // the margins are inside mWidget itself QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 ); mWidget = new WarningConfiguration( this ); vlay->addWidget( mWidget ); connect( mWidget->warnGroupBox, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); connect( mWidget->mWarnUnsigned, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); connect( mWidget->warnUnencryptedCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); connect( mWidget->warnReceiverNotInCertificateCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); connect( mWidget->mWarnSignKeyExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnSignChainCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnSignRootCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnEncrKeyExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnEncrChainCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnEncrRootCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->enableAllWarningsPB, SIGNAL(clicked()), SLOT(slotReenableAllWarningsClicked()) ); } void SecurityPage::WarningTab::doLoadOther() { const KConfigGroup composer( KMKernel::config(), "Composer" ); mWidget->warnUnencryptedCB->setChecked( composer.readBoolEntry( "crypto-warning-unencrypted", false ) ); mWidget->mWarnUnsigned->setChecked( composer.readBoolEntry( "crypto-warning-unsigned", false ) ); mWidget->warnReceiverNotInCertificateCB->setChecked( composer.readBoolEntry( "crypto-warn-recv-not-in-cert", true ) ); // The "-int" part of the key name is because there used to be a separate boolean // config entry for enabling/disabling. This is done with the single bool value now. mWidget->warnGroupBox->setChecked( composer.readBoolEntry( "crypto-warn-when-near-expire", true ) ); mWidget->mWarnSignKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-key-near-expire-int", 14 ) ); mWidget->mWarnSignChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int", 14 ) ); mWidget->mWarnSignRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-root-near-expire-int", 14 ) ); mWidget->mWarnEncrKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-key-near-expire-int", 14 ) ); mWidget->mWarnEncrChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int", 14 ) ); mWidget->mWarnEncrRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-root-near-expire-int", 14 ) ); mWidget->enableAllWarningsPB->setEnabled( true ); } void SecurityPage::WarningTab::installProfile( KConfig * profile ) { const KConfigGroup composer( profile, "Composer" ); if ( composer.hasKey( "crypto-warning-unencrypted" ) ) mWidget->warnUnencryptedCB->setChecked( composer.readBoolEntry( "crypto-warning-unencrypted" ) ); if ( composer.hasKey( "crypto-warning-unsigned" ) ) mWidget->mWarnUnsigned->setChecked( composer.readBoolEntry( "crypto-warning-unsigned" ) ); if ( composer.hasKey( "crypto-warn-recv-not-in-cert" ) ) mWidget->warnReceiverNotInCertificateCB->setChecked( composer.readBoolEntry( "crypto-warn-recv-not-in-cert" ) ); if ( composer.hasKey( "crypto-warn-when-near-expire" ) ) mWidget->warnGroupBox->setChecked( composer.readBoolEntry( "crypto-warn-when-near-expire" ) ); if ( composer.hasKey( "crypto-warn-sign-key-near-expire-int" ) ) mWidget->mWarnSignKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-key-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-sign-chaincert-near-expire-int" ) ) mWidget->mWarnSignChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-sign-root-near-expire-int" ) ) mWidget->mWarnSignRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-root-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-encr-key-near-expire-int" ) ) mWidget->mWarnEncrKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-key-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-encr-chaincert-near-expire-int" ) ) mWidget->mWarnEncrChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-encr-root-near-expire-int" ) ) mWidget->mWarnEncrRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-root-near-expire-int" ) ); } void SecurityPage::WarningTab::save() { KConfigGroup composer( KMKernel::config(), "Composer" ); composer.writeEntry( "crypto-warn-recv-not-in-cert", mWidget->warnReceiverNotInCertificateCB->isChecked() ); composer.writeEntry( "crypto-warning-unencrypted", mWidget->warnUnencryptedCB->isChecked() ); composer.writeEntry( "crypto-warning-unsigned", mWidget->mWarnUnsigned->isChecked() ); composer.writeEntry( "crypto-warn-when-near-expire", mWidget->warnGroupBox->isChecked() ); composer.writeEntry( "crypto-warn-sign-key-near-expire-int", mWidget->mWarnSignKeyExpiresSB->value() ); composer.writeEntry( "crypto-warn-sign-chaincert-near-expire-int", mWidget->mWarnSignChainCertExpiresSB->value() ); composer.writeEntry( "crypto-warn-sign-root-near-expire-int", mWidget->mWarnSignRootCertExpiresSB->value() ); composer.writeEntry( "crypto-warn-encr-key-near-expire-int", mWidget->mWarnEncrKeyExpiresSB->value() ); composer.writeEntry( "crypto-warn-encr-chaincert-near-expire-int", mWidget->mWarnEncrChainCertExpiresSB->value() ); composer.writeEntry( "crypto-warn-encr-root-near-expire-int", mWidget->mWarnEncrRootCertExpiresSB->value() ); } void SecurityPage::WarningTab::slotReenableAllWarningsClicked() { KMessageBox::enableAllMessages(); mWidget->enableAllWarningsPB->setEnabled( false ); } //// QString SecurityPage::SMimeTab::helpAnchor() const { return QString::fromLatin1("configure-security-smime-validation"); } SecurityPageSMimeTab::SecurityPageSMimeTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // the margins are inside mWidget itself QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 ); mWidget = new SMimeConfiguration( this ); vlay->addWidget( mWidget ); // Button-group for exclusive radiobuttons QButtonGroup* bg = new QButtonGroup( mWidget ); bg->hide(); bg->insert( mWidget->CRLRB ); bg->insert( mWidget->OCSPRB ); // Settings for the keyrequester custom widget mWidget->OCSPResponderSignature->setAllowedKeys( Kleo::KeySelectionDialog::SMIMEKeys | Kleo::KeySelectionDialog::TrustedKeys | Kleo::KeySelectionDialog::ValidKeys | Kleo::KeySelectionDialog::SigningKeys | Kleo::KeySelectionDialog::PublicKeys ); mWidget->OCSPResponderSignature->setMultipleKeysEnabled( false ); mConfig = Kleo::CryptoBackendFactory::instance()->config(); connect( mWidget->CRLRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->OCSPRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->OCSPResponderURL, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->OCSPResponderSignature, SIGNAL( changed() ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->doNotCheckCertPolicyCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->neverConsultCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->fetchMissingCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->ignoreServiceURLCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->ignoreHTTPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->disableHTTPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->honorHTTPProxyRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->useCustomHTTPProxyRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->customHTTPProxy, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->ignoreLDAPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->disableLDAPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->customLDAPProxy, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->disableHTTPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotUpdateHTTPActions() ) ); connect( mWidget->ignoreHTTPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotUpdateHTTPActions() ) ); // Button-group for exclusive radiobuttons QButtonGroup* bgHTTPProxy = new QButtonGroup( mWidget ); bgHTTPProxy->hide(); bgHTTPProxy->insert( mWidget->honorHTTPProxyRB ); bgHTTPProxy->insert( mWidget->useCustomHTTPProxyRB ); if ( !connectDCOPSignal( 0, "KPIM::CryptoConfig", "changed()", "load()", false ) ) kdError(5650) << "SecurityPageSMimeTab: connection to CryptoConfig's changed() failed" << endl; } SecurityPageSMimeTab::~SecurityPageSMimeTab() { } static void disableDirmngrWidget( QWidget* w ) { w->setEnabled( false ); QWhatsThis::remove( w ); QWhatsThis::add( w, i18n( "This option requires dirmngr >= 0.9.0" ) ); } static void initializeDirmngrCheckbox( QCheckBox* cb, Kleo::CryptoConfigEntry* entry ) { if ( entry ) cb->setChecked( entry->boolValue() ); else disableDirmngrWidget( cb ); } struct SMIMECryptoConfigEntries { SMIMECryptoConfigEntries( Kleo::CryptoConfig* config ) : mConfig( config ) { // Checkboxes mCheckUsingOCSPConfigEntry = configEntry( "gpgsm", "Security", "enable-ocsp", Kleo::CryptoConfigEntry::ArgType_None, false ); mEnableOCSPsendingConfigEntry = configEntry( "dirmngr", "OCSP", "allow-ocsp", Kleo::CryptoConfigEntry::ArgType_None, false ); mDoNotCheckCertPolicyConfigEntry = configEntry( "gpgsm", "Security", "disable-policy-checks", Kleo::CryptoConfigEntry::ArgType_None, false ); mNeverConsultConfigEntry = configEntry( "gpgsm", "Security", "disable-crl-checks", Kleo::CryptoConfigEntry::ArgType_None, false ); mFetchMissingConfigEntry = configEntry( "gpgsm", "Security", "auto-issuer-key-retrieve", Kleo::CryptoConfigEntry::ArgType_None, false ); // dirmngr-0.9.0 options mIgnoreServiceURLEntry = configEntry( "dirmngr", "OCSP", "ignore-ocsp-service-url", Kleo::CryptoConfigEntry::ArgType_None, false ); mIgnoreHTTPDPEntry = configEntry( "dirmngr", "HTTP", "ignore-http-dp", Kleo::CryptoConfigEntry::ArgType_None, false ); mDisableHTTPEntry = configEntry( "dirmngr", "HTTP", "disable-http", Kleo::CryptoConfigEntry::ArgType_None, false ); mHonorHTTPProxy = configEntry( "dirmngr", "HTTP", "honor-http-proxy", Kleo::CryptoConfigEntry::ArgType_None, false ); mIgnoreLDAPDPEntry = configEntry( "dirmngr", "LDAP", "ignore-ldap-dp", Kleo::CryptoConfigEntry::ArgType_None, false ); mDisableLDAPEntry = configEntry( "dirmngr", "LDAP", "disable-ldap", Kleo::CryptoConfigEntry::ArgType_None, false ); // Other widgets mOCSPResponderURLConfigEntry = configEntry( "dirmngr", "OCSP", "ocsp-responder", Kleo::CryptoConfigEntry::ArgType_String, false ); mOCSPResponderSignature = configEntry( "dirmngr", "OCSP", "ocsp-signer", Kleo::CryptoConfigEntry::ArgType_String, false ); mCustomHTTPProxy = configEntry( "dirmngr", "HTTP", "http-proxy", Kleo::CryptoConfigEntry::ArgType_String, false ); mCustomLDAPProxy = configEntry( "dirmngr", "LDAP", "ldap-proxy", Kleo::CryptoConfigEntry::ArgType_String, false ); } Kleo::CryptoConfigEntry* configEntry( const char* componentName, const char* groupName, const char* entryName, int argType, bool isList ); // Checkboxes Kleo::CryptoConfigEntry* mCheckUsingOCSPConfigEntry; Kleo::CryptoConfigEntry* mEnableOCSPsendingConfigEntry; Kleo::CryptoConfigEntry* mDoNotCheckCertPolicyConfigEntry; Kleo::CryptoConfigEntry* mNeverConsultConfigEntry; Kleo::CryptoConfigEntry* mFetchMissingConfigEntry; Kleo::CryptoConfigEntry* mIgnoreServiceURLEntry; Kleo::CryptoConfigEntry* mIgnoreHTTPDPEntry; Kleo::CryptoConfigEntry* mDisableHTTPEntry; Kleo::CryptoConfigEntry* mHonorHTTPProxy; Kleo::CryptoConfigEntry* mIgnoreLDAPDPEntry; Kleo::CryptoConfigEntry* mDisableLDAPEntry; // Other widgets Kleo::CryptoConfigEntry* mOCSPResponderURLConfigEntry; Kleo::CryptoConfigEntry* mOCSPResponderSignature; Kleo::CryptoConfigEntry* mCustomHTTPProxy; Kleo::CryptoConfigEntry* mCustomLDAPProxy; Kleo::CryptoConfig* mConfig; }; void SecurityPage::SMimeTab::doLoadOther() { if ( !mConfig ) { setEnabled( false ); return; } // Force re-parsing gpgconf data, in case e.g. kleopatra or "configure backend" was used // (which ends up calling us via dcop) mConfig->clear(); // Create config entries // Don't keep them around, they'll get deleted by clear(), which could be // done by the "configure backend" button even before we save(). SMIMECryptoConfigEntries e( mConfig ); // Initialize GUI items from the config entries if ( e.mCheckUsingOCSPConfigEntry ) { bool b = e.mCheckUsingOCSPConfigEntry->boolValue(); mWidget->OCSPRB->setChecked( b ); mWidget->CRLRB->setChecked( !b ); mWidget->OCSPGroupBox->setEnabled( b ); } else { mWidget->OCSPGroupBox->setEnabled( false ); } if ( e.mDoNotCheckCertPolicyConfigEntry ) mWidget->doNotCheckCertPolicyCB->setChecked( e.mDoNotCheckCertPolicyConfigEntry->boolValue() ); if ( e.mNeverConsultConfigEntry ) mWidget->neverConsultCB->setChecked( e.mNeverConsultConfigEntry->boolValue() ); if ( e.mFetchMissingConfigEntry ) mWidget->fetchMissingCB->setChecked( e.mFetchMissingConfigEntry->boolValue() ); if ( e.mOCSPResponderURLConfigEntry ) mWidget->OCSPResponderURL->setText( e.mOCSPResponderURLConfigEntry->stringValue() ); if ( e.mOCSPResponderSignature ) { mWidget->OCSPResponderSignature->setFingerprint( e.mOCSPResponderSignature->stringValue() ); } // dirmngr-0.9.0 options initializeDirmngrCheckbox( mWidget->ignoreServiceURLCB, e.mIgnoreServiceURLEntry ); initializeDirmngrCheckbox( mWidget->ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry ); initializeDirmngrCheckbox( mWidget->disableHTTPCB, e.mDisableHTTPEntry ); initializeDirmngrCheckbox( mWidget->ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry ); initializeDirmngrCheckbox( mWidget->disableLDAPCB, e.mDisableLDAPEntry ); if ( e.mCustomHTTPProxy ) { QString systemProxy = QString::fromLocal8Bit( getenv( "http_proxy" ) ); if ( systemProxy.isEmpty() ) systemProxy = i18n( "no proxy" ); mWidget->systemHTTPProxy->setText( i18n( "(Current system setting: %1)" ).arg( systemProxy ) ); bool honor = e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue(); mWidget->honorHTTPProxyRB->setChecked( honor ); mWidget->useCustomHTTPProxyRB->setChecked( !honor ); mWidget->customHTTPProxy->setText( e.mCustomHTTPProxy->stringValue() ); } else { disableDirmngrWidget( mWidget->honorHTTPProxyRB ); disableDirmngrWidget( mWidget->useCustomHTTPProxyRB ); disableDirmngrWidget( mWidget->systemHTTPProxy ); disableDirmngrWidget( mWidget->customHTTPProxy ); } if ( e.mCustomLDAPProxy ) mWidget->customLDAPProxy->setText( e.mCustomLDAPProxy->stringValue() ); else { disableDirmngrWidget( mWidget->customLDAPProxy ); disableDirmngrWidget( mWidget->customLDAPLabel ); } slotUpdateHTTPActions(); } void SecurityPage::SMimeTab::slotUpdateHTTPActions() { mWidget->ignoreHTTPDPCB->setEnabled( !mWidget->disableHTTPCB->isChecked() ); // The proxy settings only make sense when "Ignore HTTP CRL DPs of certificate" is checked. bool enableProxySettings = !mWidget->disableHTTPCB->isChecked() && mWidget->ignoreHTTPDPCB->isChecked(); mWidget->systemHTTPProxy->setEnabled( enableProxySettings ); mWidget->useCustomHTTPProxyRB->setEnabled( enableProxySettings ); mWidget->honorHTTPProxyRB->setEnabled( enableProxySettings ); mWidget->customHTTPProxy->setEnabled( enableProxySettings ); } void SecurityPage::SMimeTab::installProfile( KConfig * ) { } static void saveCheckBoxToKleoEntry( QCheckBox* cb, Kleo::CryptoConfigEntry* entry ) { const bool b = cb->isChecked(); if ( entry && entry->boolValue() != b ) entry->setBoolValue( b ); } void SecurityPage::SMimeTab::save() { if ( !mConfig ) { return; } // Create config entries // Don't keep them around, they'll get deleted by clear(), which could be done by the // "configure backend" button. SMIMECryptoConfigEntries e( mConfig ); bool b = mWidget->OCSPRB->isChecked(); if ( e.mCheckUsingOCSPConfigEntry && e.mCheckUsingOCSPConfigEntry->boolValue() != b ) e.mCheckUsingOCSPConfigEntry->setBoolValue( b ); // Set allow-ocsp together with enable-ocsp if ( e.mEnableOCSPsendingConfigEntry && e.mEnableOCSPsendingConfigEntry->boolValue() != b ) e.mEnableOCSPsendingConfigEntry->setBoolValue( b ); saveCheckBoxToKleoEntry( mWidget->doNotCheckCertPolicyCB, e.mDoNotCheckCertPolicyConfigEntry ); saveCheckBoxToKleoEntry( mWidget->neverConsultCB, e.mNeverConsultConfigEntry ); saveCheckBoxToKleoEntry( mWidget->fetchMissingCB, e.mFetchMissingConfigEntry ); QString txt = mWidget->OCSPResponderURL->text(); if ( e.mOCSPResponderURLConfigEntry && e.mOCSPResponderURLConfigEntry->stringValue() != txt ) e.mOCSPResponderURLConfigEntry->setStringValue( txt ); txt = mWidget->OCSPResponderSignature->fingerprint(); if ( e.mOCSPResponderSignature && e.mOCSPResponderSignature->stringValue() != txt ) { e.mOCSPResponderSignature->setStringValue( txt ); } //dirmngr-0.9.0 options saveCheckBoxToKleoEntry( mWidget->ignoreServiceURLCB, e.mIgnoreServiceURLEntry ); saveCheckBoxToKleoEntry( mWidget->ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry ); saveCheckBoxToKleoEntry( mWidget->disableHTTPCB, e.mDisableHTTPEntry ); saveCheckBoxToKleoEntry( mWidget->ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry ); saveCheckBoxToKleoEntry( mWidget->disableLDAPCB, e.mDisableLDAPEntry ); if ( e.mCustomHTTPProxy ) { const bool honor = mWidget->honorHTTPProxyRB->isChecked(); if ( e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue() != honor ) e.mHonorHTTPProxy->setBoolValue( honor ); QString chosenProxy = mWidget->customHTTPProxy->text(); if ( chosenProxy != e.mCustomHTTPProxy->stringValue() ) e.mCustomHTTPProxy->setStringValue( chosenProxy ); } txt = mWidget->customLDAPProxy->text(); if ( e.mCustomLDAPProxy && e.mCustomLDAPProxy->stringValue() != txt ) e.mCustomLDAPProxy->setStringValue( mWidget->customLDAPProxy->text() ); mConfig->sync( true ); } bool SecurityPageSMimeTab::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData) { if ( fun == "load()" ) { replyType = "void"; load(); } else { return DCOPObject::process( fun, data, replyType, replyData ); } return true; } QCStringList SecurityPageSMimeTab::interfaces() { QCStringList ifaces = DCOPObject::interfaces(); ifaces += "SecurityPageSMimeTab"; return ifaces; } QCStringList SecurityPageSMimeTab::functions() { // Hide our slot, just because it's simpler to do so. return DCOPObject::functions(); } Kleo::CryptoConfigEntry* SMIMECryptoConfigEntries::configEntry( const char* componentName, const char* groupName, const char* entryName, int /*Kleo::CryptoConfigEntry::ArgType*/ argType, bool isList ) { Kleo::CryptoConfigEntry* entry = mConfig->entry( componentName, groupName, entryName ); if ( !entry ) { kdWarning(5006) << QString( "Backend error: gpgconf doesn't seem to know the entry for %1/%2/%3" ).arg( componentName, groupName, entryName ) << endl; return 0; } if( entry->argType() != argType || entry->isList() != isList ) { kdWarning(5006) << QString( "Backend error: gpgconf has wrong type for %1/%2/%3: %4 %5" ).arg( componentName, groupName, entryName ).arg( entry->argType() ).arg( entry->isList() ) << endl; return 0; } return entry; } //// QString SecurityPage::CryptPlugTab::helpAnchor() const { return QString::fromLatin1("configure-security-crypto-backends"); } SecurityPageCryptPlugTab::SecurityPageCryptPlugTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); mBackendConfig = Kleo::CryptoBackendFactory::instance()->configWidget( this, "mBackendConfig" ); connect( mBackendConfig, SIGNAL( changed( bool ) ), this, SIGNAL( changed( bool ) ) ); vlay->addWidget( mBackendConfig ); } SecurityPageCryptPlugTab::~SecurityPageCryptPlugTab() { } void SecurityPage::CryptPlugTab::doLoadOther() { mBackendConfig->load(); } void SecurityPage::CryptPlugTab::save() { mBackendConfig->save(); } // ************************************************************* // * * // * MiscPage * // * * // ************************************************************* QString MiscPage::helpAnchor() const { return QString::fromLatin1("configure-misc"); } MiscPage::MiscPage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { mFolderTab = new FolderTab(); addTab( mFolderTab, i18n("&Folders") ); mGroupwareTab = new GroupwareTab(); addTab( mGroupwareTab, i18n("&Groupware") ); load(); } QString MiscPage::FolderTab::helpAnchor() const { return QString::fromLatin1("configure-misc-folders"); } MiscPageFolderTab::MiscPageFolderTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // temp. vars: QVBoxLayout *vlay; QHBoxLayout *hlay; QLabel *label; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "confirm before emptying folder" check box: stretch 0 mEmptyFolderConfirmCheck = new QCheckBox( i18n("Corresponds to Folder->Move All Messages to Trash", "Ask for co&nfirmation before moving all messages to " "trash"), this ); vlay->addWidget( mEmptyFolderConfirmCheck ); connect( mEmptyFolderConfirmCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mExcludeImportantFromExpiry = new QCheckBox( i18n("E&xclude important messages from expiry"), this ); vlay->addWidget( mExcludeImportantFromExpiry ); connect( mExcludeImportantFromExpiry, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "when trying to find unread messages" combo + label: stretch 0 hlay = new QHBoxLayout( vlay ); // inherits spacing mLoopOnGotoUnread = new QComboBox( false, this ); label = new QLabel( mLoopOnGotoUnread, i18n("to be continued with \"do not loop\", \"loop in current folder\", " "and \"loop in all folders\".", "When trying to find unread messages:"), this ); mLoopOnGotoUnread->insertStringList( QStringList() << i18n("continuation of \"When trying to find unread messages:\"", "Do not Loop") << i18n("continuation of \"When trying to find unread messages:\"", "Loop in Current Folder") << i18n("continuation of \"When trying to find unread messages:\"", "Loop in All Folders")); hlay->addWidget( label ); hlay->addWidget( mLoopOnGotoUnread, 1 ); connect( mLoopOnGotoUnread, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // when entering a folder hlay = new QHBoxLayout( vlay ); // inherits spacing mActionEnterFolder = new QComboBox( false, this ); label = new QLabel( mActionEnterFolder, i18n("to be continued with \"jump to first new message\", " "\"jump to first unread or new message\"," "and \"jump to last selected message\".", "When entering a folder:"), this ); mActionEnterFolder->insertStringList( QStringList() << i18n("continuation of \"When entering a folder:\"", "Jump to Most Recent New Message") << i18n("continuation of \"When entering a folder:\"", "Jump to Oldest New Message") << i18n("continuation of \"When entering a folder:\"", "Jump to Most Recent Unread or New Message") << i18n("continuation of \"When entering a folder:\"", "Jump to Oldest Unread or New Message") << i18n("continuation of \"When entering a folder:\"", "Jump to Last Selected Message") << i18n("continuation of \"When entering a folder:\"", "Jump to Most Recent Message") << i18n("continuation of \"When entering a folder:\"", "Jump to Oldest Message") ); hlay->addWidget( label ); hlay->addWidget( mActionEnterFolder, 1 ); connect( mActionEnterFolder, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); hlay = new QHBoxLayout( vlay ); // inherits spacing mDelayedMarkAsRead = new QCheckBox( i18n("Mar&k selected message as read after"), this ); hlay->addWidget( mDelayedMarkAsRead ); mDelayedMarkTime = new KIntSpinBox( 0 /*min*/, 60 /*max*/, 1/*step*/, 0 /*init*/, 10 /*base*/, this); mDelayedMarkTime->setSuffix( i18n(" sec") ); mDelayedMarkTime->setEnabled( false ); // since mDelayedMarkAsREad is off hlay->addWidget( mDelayedMarkTime ); hlay->addStretch( 1 ); connect( mDelayedMarkTime, SIGNAL( valueChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mDelayedMarkAsRead, SIGNAL(toggled(bool)), mDelayedMarkTime, SLOT(setEnabled(bool))); connect( mDelayedMarkAsRead, SIGNAL(toggled(bool)), this , SLOT(slotEmitChanged( void ))); // "show popup after Drag'n'Drop" checkbox: stretch 0 mShowPopupAfterDnD = new QCheckBox( i18n("Ask for action after &dragging messages to another folder"), this ); vlay->addWidget( mShowPopupAfterDnD ); connect( mShowPopupAfterDnD, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "default mailbox format" combo + label: stretch 0 hlay = new QHBoxLayout( vlay ); // inherits spacing mMailboxPrefCombo = new QComboBox( false, this ); label = new QLabel( mMailboxPrefCombo, i18n("to be continued with \"flat files\" and " "\"directories\", resp.", "By default, &message folders on disk are:"), this ); mMailboxPrefCombo->insertStringList( QStringList() << i18n("continuation of \"By default, &message folders on disk are\"", "Flat Files (\"mbox\" format)") << i18n("continuation of \"By default, &message folders on disk are\"", "Directories (\"maildir\" format)") ); // and now: add QWhatsThis: QString msg = i18n( "what's this help", "

This selects which mailbox format will be " "the default for local folders:

" "

mbox: KMail's mail " "folders are represented by a single file each. " "Individual messages are separated from each other by a " "line starting with \"From \". This saves space on " "disk, but may be less robust, e.g. when moving messages " "between folders.

" "

maildir: KMail's mail folders are " "represented by real folders on disk. Individual messages " "are separate files. This may waste a bit of space on " "disk, but should be more robust, e.g. when moving " "messages between folders.

"); QWhatsThis::add( mMailboxPrefCombo, msg ); QWhatsThis::add( label, msg ); hlay->addWidget( label ); hlay->addWidget( mMailboxPrefCombo, 1 ); connect( mMailboxPrefCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "On startup..." option: hlay = new QHBoxLayout( vlay ); // inherits spacing mOnStartupOpenFolder = new FolderRequester( this, kmkernel->getKMMainWidget()->folderTree() ); label = new QLabel( mOnStartupOpenFolder, i18n("Open this folder on startup:"), this ); hlay->addWidget( label ); hlay->addWidget( mOnStartupOpenFolder, 1 ); connect( mOnStartupOpenFolder, SIGNAL( folderChanged( KMFolder* ) ), this, SLOT( slotEmitChanged( void ) ) ); // "Empty &trash on program exit" option: hlay = new QHBoxLayout( vlay ); // inherits spacing mEmptyTrashCheck = new QCheckBox( i18n("Empty local &trash folder on program exit"), this ); hlay->addWidget( mEmptyTrashCheck ); connect( mEmptyTrashCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); #ifdef HAVE_INDEXLIB // indexing enabled option: mIndexingEnabled = new QCheckBox( i18n("Enable full text &indexing"), this ); vlay->addWidget( mIndexingEnabled ); connect( mIndexingEnabled, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); #endif // "Quota Units" hlay = new QHBoxLayout( vlay ); // inherits spacing mQuotaCmbBox = new QComboBox( false, this ); label = new QLabel( mQuotaCmbBox, i18n("Quota units: "), this ); mQuotaCmbBox->insertStringList( QStringList() << i18n("KB") << i18n("MB") << i18n("GB") ); hlay->addWidget( label ); hlay->addWidget( mQuotaCmbBox, 1 ); connect( mQuotaCmbBox, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addStretch( 1 ); // @TODO: Till, move into .kcgc file msg = i18n( "what's this help", "

When jumping to the next unread message, it may occur " "that no more unread messages are below the current message.

" "

Do not loop: The search will stop at the last message in " "the current folder.

" "

Loop in current folder: The search will continue at the " "top of the message list, but not go to another folder.

" "

Loop in all folders: The search will continue at the top of " "the message list. If no unread messages are found it will then continue " "to the next folder.

" "

Similarly, when searching for the previous unread message, " "the search will start from the bottom of the message list and continue to " "the previous folder depending on which option is selected.

" ); QWhatsThis::add( mLoopOnGotoUnread, msg ); #ifdef HAVE_INDEXLIB // this is probably overly pessimistic msg = i18n( "what's this help", "

Full text indexing allows very fast searches on the content " "of your messages. When enabled, the search dialog will work very fast. " "Also, the search tool bar will select messages based on content.

" "

It takes up a certain amount of disk space " "(about half the disk space for the messages).

" "

After enabling, the index will need to be built, but you can continue to use KMail " "while this operation is running.

" "
" ); QWhatsThis::add( mIndexingEnabled, msg ); #endif } void MiscPage::FolderTab::doLoadFromGlobalSettings() { mExcludeImportantFromExpiry->setChecked( GlobalSettings::self()->excludeImportantMailFromExpiry() ); // default = "Loop in current folder" mLoopOnGotoUnread->setCurrentItem( GlobalSettings::self()->loopOnGotoUnread() ); mActionEnterFolder->setCurrentItem( GlobalSettings::self()->actionEnterFolder() ); mDelayedMarkAsRead->setChecked( GlobalSettings::self()->delayedMarkAsRead() ); mDelayedMarkTime->setValue( GlobalSettings::self()->delayedMarkTime() ); mShowPopupAfterDnD->setChecked( GlobalSettings::self()->showPopupAfterDnD() ); mQuotaCmbBox->setCurrentItem( GlobalSettings::self()->quotaUnit() ); } void MiscPage::FolderTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General" ); mEmptyTrashCheck->setChecked( general.readBoolEntry( "empty-trash-on-exit", true ) ); mOnStartupOpenFolder->setFolder( general.readEntry( "startupFolder", kmkernel->inboxFolder()->idString() ) ); mEmptyFolderConfirmCheck->setChecked( general.readBoolEntry( "confirm-before-empty", true ) ); int num = general.readNumEntry("default-mailbox-format", 1 ); if ( num < 0 || num > 1 ) num = 1; mMailboxPrefCombo->setCurrentItem( num ); #ifdef HAVE_INDEXLIB mIndexingEnabled->setChecked( kmkernel->msgIndex() && kmkernel->msgIndex()->isEnabled() ); #endif } void MiscPage::FolderTab::save() { KConfigGroup general( KMKernel::config(), "General" ); general.writeEntry( "empty-trash-on-exit", mEmptyTrashCheck->isChecked() ); general.writeEntry( "confirm-before-empty", mEmptyFolderConfirmCheck->isChecked() ); general.writeEntry( "default-mailbox-format", mMailboxPrefCombo->currentItem() ); general.writeEntry( "startupFolder", mOnStartupOpenFolder->folder() ? mOnStartupOpenFolder->folder()->idString() : QString::null ); GlobalSettings::self()->setDelayedMarkAsRead( mDelayedMarkAsRead->isChecked() ); GlobalSettings::self()->setDelayedMarkTime( mDelayedMarkTime->value() ); GlobalSettings::self()->setActionEnterFolder( mActionEnterFolder->currentItem() ); GlobalSettings::self()->setLoopOnGotoUnread( mLoopOnGotoUnread->currentItem() ); GlobalSettings::self()->setShowPopupAfterDnD( mShowPopupAfterDnD->isChecked() ); GlobalSettings::self()->setExcludeImportantMailFromExpiry( mExcludeImportantFromExpiry->isChecked() ); GlobalSettings::self()->setQuotaUnit( mQuotaCmbBox->currentItem() ); #ifdef HAVE_INDEXLIB if ( kmkernel->msgIndex() ) kmkernel->msgIndex()->setEnabled( mIndexingEnabled->isChecked() ); #endif } QString MiscPage::GroupwareTab::helpAnchor() const { return QString::fromLatin1("configure-misc-groupware"); } MiscPageGroupwareTab::MiscPageGroupwareTab( QWidget* parent, const char* name ) : ConfigModuleTab( parent, name ) { QBoxLayout* vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); vlay->setAutoAdd( true ); // IMAP resource setup QVGroupBox* b1 = new QVGroupBox( i18n("&IMAP Resource Folder Options"), this ); mEnableImapResCB = new QCheckBox( i18n("&Enable IMAP resource functionality"), b1 ); QToolTip::add( mEnableImapResCB, i18n( "This enables the IMAP storage for " "the Kontact applications" ) ); QWhatsThis::add( mEnableImapResCB, i18n( GlobalSettings::self()->theIMAPResourceEnabledItem()->whatsThis().utf8() ) ); connect( mEnableImapResCB, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mBox = new QWidget( b1 ); QGridLayout* grid = new QGridLayout( mBox, 5, 2, 0, KDialog::spacingHint() ); grid->setColStretch( 1, 1 ); connect( mEnableImapResCB, SIGNAL( toggled(bool) ), mBox, SLOT( setEnabled(bool) ) ); QLabel* storageFormatLA = new QLabel( i18n("&Format used for the groupware folders:"), mBox ); QString toolTip = i18n( "Choose the format to use to store the contents of the groupware folders." ); QString whatsThis = i18n( GlobalSettings::self() ->theIMAPResourceStorageFormatItem()->whatsThis().utf8() ); grid->addWidget( storageFormatLA, 0, 0 ); QToolTip::add( storageFormatLA, toolTip ); QWhatsThis::add( storageFormatLA, whatsThis ); mStorageFormatCombo = new QComboBox( false, mBox ); storageFormatLA->setBuddy( mStorageFormatCombo ); QStringList formatLst; formatLst << i18n("Deprecated Kolab1 (iCal/vCard)") << i18n("Kolab2 (XML)"); mStorageFormatCombo->insertStringList( formatLst ); grid->addWidget( mStorageFormatCombo, 0, 1 ); QToolTip::add( mStorageFormatCombo, toolTip ); QWhatsThis::add( mStorageFormatCombo, whatsThis ); connect( mStorageFormatCombo, SIGNAL( activated( int ) ), this, SLOT( slotStorageFormatChanged( int ) ) ); QLabel* languageLA = new QLabel( i18n("&Language of the groupware folders:"), mBox ); toolTip = i18n( "Set the language of the folder names" ); whatsThis = i18n( GlobalSettings::self() ->theIMAPResourceFolderLanguageItem()->whatsThis().utf8() ); grid->addWidget( languageLA, 1, 0 ); QToolTip::add( languageLA, toolTip ); QWhatsThis::add( languageLA, whatsThis ); mLanguageCombo = new QComboBox( false, mBox ); languageLA->setBuddy( mLanguageCombo ); QStringList lst; lst << i18n("English") << i18n("German") << i18n("French") << i18n("Dutch"); mLanguageCombo->insertStringList( lst ); grid->addWidget( mLanguageCombo, 1, 1 ); QToolTip::add( mLanguageCombo, toolTip ); QWhatsThis::add( mLanguageCombo, whatsThis ); connect( mLanguageCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mFolderComboLabel = new QLabel( mBox ); // text depends on storage format toolTip = i18n( "Set the parent of the resource folders" ); whatsThis = i18n( GlobalSettings::self()->theIMAPResourceFolderParentItem()->whatsThis().utf8() ); QToolTip::add( mFolderComboLabel, toolTip ); QWhatsThis::add( mFolderComboLabel, whatsThis ); grid->addWidget( mFolderComboLabel, 2, 0 ); mFolderComboStack = new QWidgetStack( mBox ); grid->addWidget( mFolderComboStack, 2, 1 ); // First possibility in the widgetstack: a combo showing the list of all folders // This is used with the ical/vcard storage mFolderCombo = new FolderRequester( mBox, kmkernel->getKMMainWidget()->folderTree() ); mFolderComboStack->addWidget( mFolderCombo, 0 ); QToolTip::add( mFolderCombo, toolTip ); QWhatsThis::add( mFolderCombo, whatsThis ); connect( mFolderCombo, SIGNAL( folderChanged( KMFolder* ) ), this, SLOT( slotEmitChanged() ) ); // Second possibility in the widgetstack: a combo showing the list of accounts // This is used with the kolab xml storage since the groupware folders // are always under the inbox. mAccountCombo = new KMail::AccountComboBox( mBox ); mFolderComboStack->addWidget( mAccountCombo, 1 ); QToolTip::add( mAccountCombo, toolTip ); QWhatsThis::add( mAccountCombo, whatsThis ); connect( mAccountCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged() ) ); mHideGroupwareFolders = new QCheckBox( i18n( "&Hide groupware folders" ), mBox, "HideGroupwareFoldersBox" ); grid->addMultiCellWidget( mHideGroupwareFolders, 3, 3, 0, 0 ); QToolTip::add( mHideGroupwareFolders, i18n( "When this is checked, you will not see the IMAP " "resource folders in the folder tree." ) ); QWhatsThis::add( mHideGroupwareFolders, i18n( GlobalSettings::self() ->hideGroupwareFoldersItem()->whatsThis().utf8() ) ); connect( mHideGroupwareFolders, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); mOnlyShowGroupwareFolders = new QCheckBox( i18n( "&Only show groupware folders for this account" ), mBox, "OnlyGroupwareFoldersBox" ); grid->addMultiCellWidget( mOnlyShowGroupwareFolders, 3, 3, 1, 1 ); QToolTip::add( mOnlyShowGroupwareFolders, i18n( "When this is checked, you will not see normal " "mail folders in the folder tree for the account " "configured for groupware." ) ); QWhatsThis::add( mOnlyShowGroupwareFolders, i18n( GlobalSettings::self() ->showOnlyGroupwareFoldersForGroupwareAccountItem()->whatsThis().utf8() ) ); connect( mOnlyShowGroupwareFolders, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); mSyncImmediately = new QCheckBox( i18n( "Synchronize groupware changes immediately" ), mBox ); QToolTip::add( mSyncImmediately, i18n( "Synchronize groupware changes in disconnected IMAP folders immediately when being online." ) ); connect( mSyncImmediately, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); grid->addMultiCellWidget( mSyncImmediately, 4, 4, 0, 1 ); mDeleteInvitations = new QCheckBox( i18n( GlobalSettings::self()->deleteInvitationEmailsAfterSendingReplyItem()->label().utf8() ), mBox ); QWhatsThis::add( mDeleteInvitations, i18n( GlobalSettings::self() ->deleteInvitationEmailsAfterSendingReplyItem()->whatsThis().utf8() ) ); connect( mDeleteInvitations, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); grid->addMultiCellWidget( mDeleteInvitations, 5, 5, 0, 1 ); // Groupware functionality compatibility setup b1 = new QVGroupBox( i18n("Groupware Compatibility && Legacy Options"), this ); gBox = new QVBox( b1 ); #if 0 // Currently believed to be disused. mEnableGwCB = new QCheckBox( i18n("&Enable groupware functionality"), b1 ); gBox->setSpacing( KDialog::spacingHint() ); connect( mEnableGwCB, SIGNAL( toggled(bool) ), gBox, SLOT( setEnabled(bool) ) ); connect( mEnableGwCB, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); #endif mEnableGwCB = 0; mLegacyMangleFromTo = new QCheckBox( i18n( "Mangle From:/To: headers in replies to invitations" ), gBox ); QToolTip::add( mLegacyMangleFromTo, i18n( "Turn this option on in order to make Outlook(tm) understand your answers to invitation replies" ) ); QWhatsThis::add( mLegacyMangleFromTo, i18n( GlobalSettings::self()-> legacyMangleFromToHeadersItem()->whatsThis().utf8() ) ); connect( mLegacyMangleFromTo, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mLegacyBodyInvites = new QCheckBox( i18n( "Send invitations in the mail body" ), gBox ); QToolTip::add( mLegacyBodyInvites, i18n( "Turn this option on in order to make Outlook(tm) understand your answers to invitations" ) ); QWhatsThis::add( mLegacyMangleFromTo, i18n( GlobalSettings::self()-> legacyBodyInvitesItem()->whatsThis().utf8() ) ); connect( mLegacyBodyInvites, SIGNAL( toggled( bool ) ), this, SLOT( slotLegacyBodyInvitesToggled( bool ) ) ); connect( mLegacyBodyInvites, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mExchangeCompatibleInvitations = new QCheckBox( i18n( "Exchange compatible invitation naming" ), gBox ); QToolTip::add( mExchangeCompatibleInvitations, i18n( "Outlook(tm), when used in combination with a Microsoft Exchange server,\nhas a problem understanding standards-compliant groupware e-mail.\nTurn this option on to send groupware invitations and replies in an Exchange compatible way." ) ); QWhatsThis::add( mExchangeCompatibleInvitations, i18n( GlobalSettings::self()-> exchangeCompatibleInvitationsItem()->whatsThis().utf8() ) ); connect( mExchangeCompatibleInvitations, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mAutomaticSending = new QCheckBox( i18n( "Automatic invitation sending" ), gBox ); QToolTip::add( mAutomaticSending, i18n( "When this is on, the user will not see the mail composer window. Invitation mails are sent automatically" ) ); QWhatsThis::add( mAutomaticSending, i18n( GlobalSettings::self()-> automaticSendingItem()->whatsThis().utf8() ) ); connect( mAutomaticSending, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // Open space padding at the end new QLabel( this ); } void MiscPageGroupwareTab::slotLegacyBodyInvitesToggled( bool on ) { if ( on ) { QString txt = i18n( "Invitations are normally sent as attachments to " "a mail. This switch changes the invitation mails to " "be sent in the text of the mail instead; this is " "necessary to send invitations and replies to " "Microsoft Outlook.
But, when you do this, you no " "longer get descriptive text that mail programs " "can read; so, to people who have email programs " "that do not understand the invitations, the " "resulting messages look very odd.
People that have email " "programs that do understand invitations will still " "be able to work with this.
" ); KMessageBox::information( this, txt, QString::null, "LegacyBodyInvitesWarning" ); } // Invitations in the body are autosent in any case (no point in editing raw ICAL) // So the autosend option is only available if invitations are sent as attachment. mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() ); } void MiscPage::GroupwareTab::doLoadFromGlobalSettings() { if ( mEnableGwCB ) { mEnableGwCB->setChecked( GlobalSettings::self()->groupwareEnabled() ); gBox->setEnabled( mEnableGwCB->isChecked() ); } mLegacyMangleFromTo->setChecked( GlobalSettings::self()->legacyMangleFromToHeaders() ); mLegacyBodyInvites->blockSignals( true ); mLegacyBodyInvites->setChecked( GlobalSettings::self()->legacyBodyInvites() ); mLegacyBodyInvites->blockSignals( false ); mExchangeCompatibleInvitations->setChecked( GlobalSettings::self()->exchangeCompatibleInvitations() ); mAutomaticSending->setChecked( GlobalSettings::self()->automaticSending() ); mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() ); // Read the IMAP resource config mEnableImapResCB->setChecked( GlobalSettings::self()->theIMAPResourceEnabled() ); mBox->setEnabled( mEnableImapResCB->isChecked() ); mHideGroupwareFolders->setChecked( GlobalSettings::self()->hideGroupwareFolders() ); int i = GlobalSettings::self()->theIMAPResourceFolderLanguage(); mLanguageCombo->setCurrentItem(i); i = GlobalSettings::self()->theIMAPResourceStorageFormat(); mStorageFormatCombo->setCurrentItem(i); slotStorageFormatChanged( i ); mOnlyShowGroupwareFolders->setChecked( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount() ); mSyncImmediately->setChecked( GlobalSettings::self()->immediatlySyncDIMAPOnGroupwareChanges() ); mDeleteInvitations->setChecked( GlobalSettings::self()->deleteInvitationEmailsAfterSendingReply() ); QString folderId( GlobalSettings::self()->theIMAPResourceFolderParent() ); if( !folderId.isNull() && kmkernel->findFolderById( folderId ) ) { mFolderCombo->setFolder( folderId ); } else { // Folder was deleted, we have to choose a new one mFolderCombo->setFolder( i18n( "" ) ); } KMAccount* selectedAccount = 0; int accountId = GlobalSettings::self()->theIMAPResourceAccount(); if ( accountId ) selectedAccount = kmkernel->acctMgr()->find( accountId ); else { // Fallback: iterate over accounts to select folderId if found (as an inbox folder) for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0; a = kmkernel->acctMgr()->next() ) { if( a->folder() && a->folder()->child() ) { // Look inside that folder for an INBOX KMFolderNode *node; for (node = a->folder()->child()->first(); node; node = a->folder()->child()->next()) if (!node->isDir() && node->name() == "INBOX") break; if ( node && static_cast(node)->idString() == folderId ) { selectedAccount = a; break; } } } } if ( selectedAccount ) mAccountCombo->setCurrentAccount( selectedAccount ); else if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == 1 ) kdDebug(5006) << "Folder " << folderId << " not found as an account's inbox" << endl; } void MiscPage::GroupwareTab::save() { KConfigGroup groupware( KMKernel::config(), "Groupware" ); // Write the groupware config if ( mEnableGwCB ) { groupware.writeEntry( "GroupwareEnabled", mEnableGwCB->isChecked() ); } groupware.writeEntry( "LegacyMangleFromToHeaders", mLegacyMangleFromTo->isChecked() ); groupware.writeEntry( "LegacyBodyInvites", mLegacyBodyInvites->isChecked() ); groupware.writeEntry( "ExchangeCompatibleInvitations", mExchangeCompatibleInvitations->isChecked() ); groupware.writeEntry( "AutomaticSending", mAutomaticSending->isChecked() ); if ( mEnableGwCB ) { GlobalSettings::self()->setGroupwareEnabled( mEnableGwCB->isChecked() ); } GlobalSettings::self()->setLegacyMangleFromToHeaders( mLegacyMangleFromTo->isChecked() ); GlobalSettings::self()->setLegacyBodyInvites( mLegacyBodyInvites->isChecked() ); GlobalSettings::self()->setExchangeCompatibleInvitations( mExchangeCompatibleInvitations->isChecked() ); GlobalSettings::self()->setAutomaticSending( mAutomaticSending->isChecked() ); int format = mStorageFormatCombo->currentItem(); GlobalSettings::self()->setTheIMAPResourceStorageFormat( format ); // Write the IMAP resource config GlobalSettings::self()->setHideGroupwareFolders( mHideGroupwareFolders->isChecked() ); GlobalSettings::self()->setShowOnlyGroupwareFoldersForGroupwareAccount( mOnlyShowGroupwareFolders->isChecked() ); GlobalSettings::self()->setImmediatlySyncDIMAPOnGroupwareChanges( mSyncImmediately->isChecked() ); GlobalSettings::self()->setDeleteInvitationEmailsAfterSendingReply( mDeleteInvitations->isChecked() ); // If there is a leftover folder in the foldercombo, getFolder can // return 0. In that case we really don't have it enabled QString folderId; if ( format == 0 ) { KMFolder* folder = mFolderCombo->folder(); if ( folder ) folderId = folder->idString(); KMAccount* account = 0; // Didn't find an easy way to find the account for a given folder... // Fallback: iterate over accounts to select folderId if found (as an inbox folder) for( KMAccount *a = kmkernel->acctMgr()->first(); a && !account; // stop when found a = kmkernel->acctMgr()->next() ) { if( a->folder() && a->folder()->child() ) { KMFolderNode *node; for ( node = a->folder()->child()->first(); node; node = a->folder()->child()->next() ) { if ( static_cast(node) == folder ) { account = a; break; } } } } GlobalSettings::self()->setTheIMAPResourceAccount( account ? account->id() : 0 ); } else { // Inbox folder of the selected account KMAccount* acct = mAccountCombo->currentAccount(); if ( acct ) { folderId = QString( ".%1.directory/INBOX" ).arg( acct->id() ); GlobalSettings::self()->setTheIMAPResourceAccount( acct->id() ); } } bool enabled = mEnableImapResCB->isChecked() && !folderId.isEmpty(); GlobalSettings::self()->setTheIMAPResourceEnabled( enabled ); GlobalSettings::self()->setTheIMAPResourceFolderLanguage( mLanguageCombo->currentItem() ); GlobalSettings::self()->setTheIMAPResourceFolderParent( folderId ); } void MiscPage::GroupwareTab::slotStorageFormatChanged( int format ) { mLanguageCombo->setEnabled( format == 0 ); // only ical/vcard needs the language hack mFolderComboStack->raiseWidget( format ); if ( format == 0 ) { mFolderComboLabel->setText( i18n("&Resource folders are subfolders of:") ); mFolderComboLabel->setBuddy( mFolderCombo ); } else { mFolderComboLabel->setText( i18n("&Resource folders are in account:") ); mFolderComboLabel->setBuddy( mAccountCombo ); } slotEmitChanged(); } // ************************************************************* // * * // * AccountUpdater * // * * // ************************************************************* AccountUpdater::AccountUpdater(ImapAccountBase *account) : QObject() { mAccount = account; } void AccountUpdater::update() { connect( mAccount, SIGNAL( connectionResult(int, const QString&) ), this, SLOT( namespacesFetched() ) ); mAccount->makeConnection(); } void AccountUpdater::namespacesFetched() { mAccount->setCheckingMail( true ); mAccount->processNewMail( false ); deleteLater(); } #undef DIM //---------------------------- #include "configuredialog.moc" diff --git a/kmail/configuredialog_p.h b/kmail/configuredialog_p.h index 2c4c2501cd..7499cb9f97 100644 --- a/kmail/configuredialog_p.h +++ b/kmail/configuredialog_p.h @@ -1,1072 +1,1073 @@ // -*- c++ -*- // configuredialog_p.h: classes internal to ConfigureDialog // see configuredialog.h for details. #ifndef _CONFIGURE_DIALOG_PRIVATE_H_ #define _CONFIGURE_DIALOG_PRIVATE_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include class QPushButton; class QLabel; class QCheckBox; class KURLRequester; class KFontChooser; class QRadioButton; class ColorListBox; class QFont; class QListViewItem; class QTabWidget; class QListBox; class QButtonGroup; class QRegExpValidator; class QVBox; class KMAccount; class KMTransportInfo; class ListView; class ConfigureDialog; class KIntSpinBox; class SimpleStringListEditor; class KConfig; class QPoint; class ComposerCryptoConfiguration; class WarningConfiguration; class SMimeConfiguration; class TemplatesConfiguration; class CustomTemplates; class QGroupBox; class QVGroupBox; #include class QLineEdit; class KMMsgTagDesc; class KListBox; class KColorCombo; class KFontRequester; class KIconButton; class KKeyButton; class QSpinBox; class KComboBox; namespace Kpgp { class Config; } namespace KMail { class IdentityDialog; class IdentityListView; class AccountComboBox; class FolderRequester; } namespace Kleo { class BackendConfigWidget; class CryptoConfig; class CryptoConfigEntry; } class NewIdentityDialog : public KDialogBase { Q_OBJECT public: enum DuplicateMode { Empty, ControlCenter, ExistingEntry }; NewIdentityDialog( const QStringList & identities, QWidget *parent=0, const char *name=0, bool modal=true ); QString identityName() const { return mLineEdit->text(); } QString duplicateIdentity() const { return mComboBox->currentText(); } DuplicateMode duplicateMode() const; protected slots: virtual void slotEnableOK( const QString & ); private: QLineEdit *mLineEdit; QComboBox *mComboBox; QButtonGroup *mButtonGroup; }; // // // Language item handling // // struct LanguageItem { LanguageItem() {} LanguageItem( const QString & language, const QString & reply=QString::null, const QString & replyAll=QString::null, const QString & forward=QString::null, const QString & indentPrefix=QString::null ) : mLanguage( language ), mReply( reply ), mReplyAll( replyAll ), mForward( forward ), mIndentPrefix( indentPrefix ) {} QString mLanguage, mReply, mReplyAll, mForward, mIndentPrefix; }; typedef QValueList LanguageItemList; class NewLanguageDialog : public KDialogBase { Q_OBJECT public: NewLanguageDialog( LanguageItemList & suppressedLangs, QWidget *parent=0, const char *name=0, bool modal=true ); QString language() const; private: QComboBox *mComboBox; }; class LanguageComboBox : public QComboBox { Q_OBJECT public: LanguageComboBox( bool rw, QWidget *parent=0, const char *name=0 ); int insertLanguage( const QString & language ); QString language() const; void setLanguage( const QString & language ); }; // // // Profile dialog // // class ProfileDialog : public KDialogBase { Q_OBJECT public: ProfileDialog( QWidget * parent=0, const char * name=0, bool modal=false ); signals: void profileSelected( KConfig * profile ); private slots: void slotSelectionChanged(); void slotOk(); private: void setup(); private: KListView *mListView; QStringList mProfileList; }; #include class ConfigModule : public KCModule { Q_OBJECT public: ConfigModule( QWidget * parent=0, const char * name=0 ) : KCModule ( parent, name ) {} ~ConfigModule() {} virtual void load() = 0; virtual void save() = 0; virtual void defaults() {} /** Should return the help anchor for this page or tab */ virtual QString helpAnchor() const = 0; signals: /** Emitted when the installation of a profile is requested. All connected kcms should load the values from the profile only for those entries that really have keys defined in the profile. */ void installProfile( KConfig * profile ); }; // Individual tab of a ConfigModuleWithTabs class ConfigModuleTab : public QWidget { Q_OBJECT public: ConfigModuleTab( QWidget *parent=0, const char* name=0 ) :QWidget( parent, name ) {} ~ConfigModuleTab() {} void load(); virtual void save() = 0; void defaults(); // the below are optional virtual void installProfile(){} signals: // forwarded to the ConfigModule void changed(bool); public slots: void slotEmitChanged(); private: // reimplement this for loading values of settings which are available // via GlobalSettings virtual void doLoadFromGlobalSettings() {} // reimplement this for loading values of settings which are not available // via GlobalSettings virtual void doLoadOther() {} // reimplement this for loading default values of settings which are // not available via GlobalSettings (KConfigXT). virtual void doResetToDefaultsOther() {} }; /* * ConfigModuleWithTabs represents a kcm with several tabs. * It simply forwards load and save operations to all tabs. */ class ConfigModuleWithTabs : public ConfigModule { Q_OBJECT public: ConfigModuleWithTabs( QWidget * parent=0, const char * name=0 ); ~ConfigModuleWithTabs() {} // don't reimplement any of those methods virtual void load(); virtual void save(); virtual void defaults(); virtual void installProfile( KConfig * profile ); protected: void addTab( ConfigModuleTab* tab, const QString & title ); private: QTabWidget *mTabWidget; }; // // // IdentityPage // // class KDE_EXPORT IdentityPage : public ConfigModule { Q_OBJECT public: IdentityPage( QWidget * parent=0, const char * name=0 ); ~IdentityPage() {} QString helpAnchor() const; void load(); void save(); public slots: void slotUpdateTransportCombo( const QStringList & ); private slots: void slotNewIdentity(); void slotModifyIdentity(); void slotRemoveIdentity(); /** Connected to @p mRenameButton's clicked() signal. Just does a KListView::rename on the selected item */ void slotRenameIdentity(); /** connected to @p mIdentityList's renamed() signal. Validates the new name and sets it in the KPIM::IdentityManager */ void slotRenameIdentity( QListViewItem *, const QString &, int ); void slotContextMenu( KListView*, QListViewItem *, const QPoint & ); void slotSetAsDefault(); void slotIdentitySelectionChanged(); private: // methods void refreshList(); private: // data members KMail::IdentityDialog * mIdentityDialog; int mOldNumberOfIdentities; KMail::IdentityListView * mIdentityList; QPushButton * mModifyButton; QPushButton * mRenameButton; QPushButton * mRemoveButton; QPushButton * mSetAsDefaultButton; }; // // // AccountsPage // // // subclasses: one class per tab: class AccountsPageSendingTab : public ConfigModuleTab { Q_OBJECT public: AccountsPageSendingTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); signals: void transportListChanged( const QStringList & ); private slots: void slotTransportSelected(); void slotAddTransport(); void slotModifySelectedTransport(); void slotRemoveSelectedTransport(); void slotSetDefaultTransport(); private: virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: ListView *mTransportList; QPushButton *mModifyTransportButton; QPushButton *mRemoveTransportButton; QPushButton *mSetDefaultTransportButton; QCheckBox *mConfirmSendCheck; QComboBox *mSendOnCheckCombo; QComboBox *mSendMethodCombo; QComboBox *mMessagePropertyCombo; QLineEdit *mDefaultDomainEdit; QPtrList< KMTransportInfo > mTransportInfoList; }; class AccountsPageReceivingTab : public ConfigModuleTab { Q_OBJECT public: AccountsPageReceivingTab( QWidget * parent=0, const char * name=0 ); ~AccountsPageReceivingTab(); QString helpAnchor() const; void save(); signals: void accountListChanged( const QStringList & ); private slots: void slotAccountSelected(); void slotAddAccount(); void slotModifySelectedAccount(); void slotRemoveSelectedAccount(); void slotEditNotifications(); void slotTweakAccountList(); private: virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); QStringList occupiedNames(); private: ListView *mAccountList; QPushButton *mModifyAccountButton; QPushButton *mRemoveAccountButton; QCheckBox *mBeepNewMailCheck; QCheckBox *mVerboseNotificationCheck; QCheckBox *mCheckmailStartupCheck; QPushButton *mOtherNewMailActionsButton; QValueList< QGuardedPtr > mAccountsToDelete; QValueList< QGuardedPtr > mNewAccounts; struct ModifiedAccountsType { QGuardedPtr< KMAccount > oldAccount; QGuardedPtr< KMAccount > newAccount; }; // ### make this value-based: QValueList< ModifiedAccountsType* > mModifiedAccounts; }; class KDE_EXPORT AccountsPage : public ConfigModuleWithTabs { Q_OBJECT public: AccountsPage( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; // hrmpf. moc doesn't like nested classes with slots/signals...: typedef AccountsPageSendingTab SendingTab; typedef AccountsPageReceivingTab ReceivingTab; signals: void transportListChanged( const QStringList & ); void accountListChanged( const QStringList & ); private: SendingTab *mSendingTab; ReceivingTab *mReceivingTab; }; // // // AppearancePage // // class AppearancePageFontsTab : public ConfigModuleTab { Q_OBJECT public: AppearancePageFontsTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private slots: void slotFontSelectorChanged( int ); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); void updateFontSelector(); private: QCheckBox *mCustomFontCheck; QComboBox *mFontLocationCombo; KFontChooser *mFontChooser; int mActiveFontIndex; QFont mFont[14]; }; class AppearancePageColorsTab : public ConfigModuleTab { Q_OBJECT public: AppearancePageColorsTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: QCheckBox *mCustomColorCheck; ColorListBox *mColorList; QCheckBox *mRecycleColorCheck; QSpinBox *mCloseToQuotaThreshold; }; class AppearancePageLayoutTab : public ConfigModuleTab { Q_OBJECT public: AppearancePageLayoutTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: // data QButtonGroup *mFolderListGroup; QButtonGroup *mMIMETreeLocationGroup; QButtonGroup *mMIMETreeModeGroup; QButtonGroup *mReaderWindowModeGroup; QCheckBox *mFavoriteFolderViewCB; }; class AppearancePageHeadersTab : public ConfigModuleTab { Q_OBJECT public: AppearancePageHeadersTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private: // methods //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); void setDateDisplay( int id, const QString & format ); private: // data QCheckBox *mMessageSizeCheck; QCheckBox *mAttachmentCheck; QCheckBox *mNestedMessagesCheck; QCheckBox *mCryptoIconsCheck; QButtonGroup *mNestingPolicy; QButtonGroup *mDateDisplay; QLineEdit *mCustomDateFormatEdit; }; class AppearancePageReaderTab : public ConfigModuleTab { Q_OBJECT public: AppearancePageReaderTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private: virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); void readCurrentFallbackCodec(); void readCurrentOverrideCodec(); private: // data QCheckBox *mCloseAfterReplyOrForwardCheck; QCheckBox *mShowColorbarCheck; QCheckBox *mShowSpamStatusCheck; QCheckBox *mShowEmoticonsCheck; QCheckBox *mShowExpandQuotesMark; KIntSpinBox *mCollapseQuoteLevelSpin; QCheckBox *mShrinkQuotesCheck; QComboBox *mCharsetCombo; QComboBox *mOverrideCharsetCombo; }; class AppearancePageSystemTrayTab : public ConfigModuleTab { Q_OBJECT public: AppearancePageSystemTrayTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private: virtual void doLoadFromGlobalSettings(); private: // data QCheckBox *mSystemTrayCheck; QButtonGroup *mSystemTrayGroup; }; class KDE_EXPORT AppearancePage : public ConfigModuleWithTabs { Q_OBJECT public: AppearancePage( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; // hrmpf. moc doesn't like nested classes with slots/signals...: typedef AppearancePageFontsTab FontsTab; typedef AppearancePageColorsTab ColorsTab; typedef AppearancePageLayoutTab LayoutTab; typedef AppearancePageHeadersTab HeadersTab; typedef AppearancePageReaderTab ReaderTab; typedef AppearancePageSystemTrayTab SystemTrayTab; private: FontsTab *mFontsTab; ColorsTab *mColorsTab; LayoutTab *mLayoutTab; HeadersTab *mHeadersTab; ReaderTab *mReaderTab; SystemTrayTab *mSystemTrayTab; }; // // // Composer Page // // class ComposerPageGeneralTab : public ConfigModuleTab { Q_OBJECT public: ComposerPageGeneralTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); protected slots: void slotConfigureRecentAddresses(); void slotConfigureCompletionOrder(); private: virtual void doLoadFromGlobalSettings(); private: QCheckBox *mAutoAppSignFileCheck; QCheckBox *mTopQuoteCheck; QCheckBox *mSmartQuoteCheck; QCheckBox *mStripSignatureCheck; QCheckBox *mQuoteSelectionOnlyCheck; QCheckBox *mAutoRequestMDNCheck; QCheckBox *mShowRecentAddressesInComposer; QCheckBox *mRemoveOwnIdentitiesCheck; QCheckBox *mWordWrapCheck; KIntSpinBox *mWrapColumnSpin; QCheckBox *mRecipientCheck; KIntSpinBox *mRecipientSpin; KIntSpinBox *mAutoSave; QCheckBox *mExternalEditorCheck; KURLRequester *mEditorRequester; KComboBox *mForwardTypeCombo; }; class ComposerPagePhrasesTab : public ConfigModuleTab { Q_OBJECT public: ComposerPagePhrasesTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); private slots: void slotNewLanguage(); void slotRemoveLanguage(); void slotLanguageChanged( const QString& ); void slotAddNewLanguage( const QString& ); private: virtual void doLoadFromGlobalSettings(); void setLanguageItemInformation( int index ); void saveActiveLanguageItem(); private: LanguageComboBox *mPhraseLanguageCombo; QPushButton *mRemoveButton; QLineEdit *mPhraseReplyEdit; QLineEdit *mPhraseReplyAllEdit; QLineEdit *mPhraseForwardEdit; QLineEdit *mPhraseIndentPrefixEdit; int mActiveLanguageItem; LanguageItemList mLanguageList; }; class ComposerPageTemplatesTab : public ConfigModuleTab { Q_OBJECT public: ComposerPageTemplatesTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); private slots: private: virtual void doLoadFromGlobalSettings(); private: TemplatesConfiguration* mWidget; }; class ComposerPageCustomTemplatesTab : public ConfigModuleTab { Q_OBJECT public: ComposerPageCustomTemplatesTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); private slots: private: virtual void doLoadFromGlobalSettings(); private: CustomTemplates* mWidget; }; class ComposerPageSubjectTab : public ConfigModuleTab { Q_OBJECT public: ComposerPageSubjectTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); private: virtual void doLoadFromGlobalSettings(); private: SimpleStringListEditor *mReplyListEditor; QCheckBox *mReplaceReplyPrefixCheck; SimpleStringListEditor *mForwardListEditor; QCheckBox *mReplaceForwardPrefixCheck; }; class ComposerPageCharsetTab : public ConfigModuleTab { Q_OBJECT public: ComposerPageCharsetTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); private slots: void slotVerifyCharset(QString&); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: SimpleStringListEditor *mCharsetListEditor; QCheckBox *mKeepReplyCharsetCheck; }; class ComposerPageHeadersTab : public ConfigModuleTab { Q_OBJECT public: ComposerPageHeadersTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); private slots: void slotMimeHeaderSelectionChanged(); void slotMimeHeaderNameChanged( const QString & ); void slotMimeHeaderValueChanged( const QString & ); void slotNewMimeHeader(); void slotRemoveMimeHeader(); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: QCheckBox *mCreateOwnMessageIdCheck; QLineEdit *mMessageIdSuffixEdit; QRegExpValidator *mMessageIdSuffixValidator; QListView *mTagList; QPushButton *mRemoveHeaderButton; QLineEdit *mTagNameEdit; QLineEdit *mTagValueEdit; QLabel *mTagNameLabel; QLabel *mTagValueLabel; }; class ComposerPageAttachmentsTab : public ConfigModuleTab { Q_OBJECT public: ComposerPageAttachmentsTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); private slots: void slotOutlookCompatibleClicked(); private: virtual void doLoadFromGlobalSettings(); //FIXME virtual void doResetToDefaultsOther(); private: QCheckBox *mOutlookCompatibleCheck; QCheckBox *mMissingAttachmentDetectionCheck; SimpleStringListEditor *mAttachWordsListEditor; }; class KDE_EXPORT ComposerPage : public ConfigModuleWithTabs { Q_OBJECT public: ComposerPage( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; // hrmpf. moc doesn't like nested classes with slots/signals...: typedef ComposerPageGeneralTab GeneralTab; typedef ComposerPagePhrasesTab PhrasesTab; typedef ComposerPageTemplatesTab TemplatesTab; typedef ComposerPageCustomTemplatesTab CustomTemplatesTab; typedef ComposerPageSubjectTab SubjectTab; typedef ComposerPageCharsetTab CharsetTab; typedef ComposerPageHeadersTab HeadersTab; typedef ComposerPageAttachmentsTab AttachmentsTab; private: GeneralTab *mGeneralTab; PhrasesTab *mPhrasesTab; TemplatesTab *mTemplatesTab; CustomTemplatesTab *mCustomTemplatesTab; SubjectTab *mSubjectTab; CharsetTab *mCharsetTab; HeadersTab *mHeadersTab; AttachmentsTab *mAttachmentsTab; }; // // // SecurityPage // // class SecurityPageGeneralTab : public ConfigModuleTab { Q_OBJECT public: SecurityPageGeneralTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: QCheckBox *mExternalReferences; QRadioButton *mHtmlMailRB; QRadioButton *mPlainMailRB; QRadioButton *mPlainWithOptionRB; QCheckBox *mNoMDNsWhenEncryptedCheck; QButtonGroup *mMDNGroup; QButtonGroup *mOrigQuoteGroup; QCheckBox *mAutomaticallyImportAttachedKeysCheck; + QCheckBox *mAutomaticallySearchForEncryptionKeys; QCheckBox *mAlwaysDecrypt; }; class SecurityPageComposerCryptoTab : public ConfigModuleTab { Q_OBJECT public: SecurityPageComposerCryptoTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: ComposerCryptoConfiguration* mWidget; }; class SecurityPageWarningTab : public ConfigModuleTab { Q_OBJECT public: SecurityPageWarningTab( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; void save(); void installProfile( KConfig * profile ); private slots: void slotReenableAllWarningsClicked(); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: WarningConfiguration* mWidget; }; class SecurityPageSMimeTab : public ConfigModuleTab, public DCOPObject { Q_OBJECT K_DCOP public: SecurityPageSMimeTab( QWidget * parent=0, const char * name=0 ); ~SecurityPageSMimeTab(); QString helpAnchor() const; // Can't use k_dcop here. dcopidl can't parse this file, dcopidlng has a namespace bug. void save(); void installProfile( KConfig * profile ); private slots: void slotUpdateHTTPActions(); private: //virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: SMimeConfiguration* mWidget; Kleo::CryptoConfig* mConfig; }; class SecurityPageCryptPlugTab : public ConfigModuleTab { Q_OBJECT public: SecurityPageCryptPlugTab( QWidget * parent = 0, const char* name = 0 ); ~SecurityPageCryptPlugTab(); QString helpAnchor() const; void save(); private: virtual void doLoadOther(); //virtual void doResetToDefaultsOther(); private: Kleo::BackendConfigWidget * mBackendConfig; }; class KDE_EXPORT SecurityPage : public ConfigModuleWithTabs { Q_OBJECT public: SecurityPage( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; // OpenPGP tab is special: void installProfile( KConfig * profile ); typedef SecurityPageGeneralTab GeneralTab; typedef SecurityPageComposerCryptoTab ComposerCryptoTab; typedef SecurityPageWarningTab WarningTab; typedef SecurityPageSMimeTab SMimeTab; typedef SecurityPageCryptPlugTab CryptPlugTab; private: GeneralTab *mGeneralTab; ComposerCryptoTab *mComposerCryptoTab; WarningTab *mWarningTab; SMimeTab *mSMimeTab; CryptPlugTab *mCryptPlugTab; }; // // // MiscPage // // class MiscPageFolderTab : public ConfigModuleTab { Q_OBJECT public: MiscPageFolderTab( QWidget * parent=0, const char * name=0 ); void save(); QString helpAnchor() const; private: virtual void doLoadFromGlobalSettings(); virtual void doLoadOther(); //FIXME virtual void doResetToDefaultsOther(); private: QCheckBox *mEmptyFolderConfirmCheck; QCheckBox *mExcludeImportantFromExpiry; QComboBox *mLoopOnGotoUnread; QComboBox *mMailboxPrefCombo; QComboBox *mActionEnterFolder; QCheckBox *mEmptyTrashCheck; #ifdef HAVE_INDEXLIB QCheckBox *mIndexingEnabled; #endif QCheckBox *mDelayedMarkAsRead; KIntSpinBox *mDelayedMarkTime; QCheckBox *mShowPopupAfterDnD; KMail::FolderRequester *mOnStartupOpenFolder; QComboBox *mQuotaCmbBox; }; class MiscPageGroupwareTab : public ConfigModuleTab { Q_OBJECT public: MiscPageGroupwareTab( QWidget * parent=0, const char * name=0 ); void save(); QString helpAnchor() const; private slots: void slotStorageFormatChanged( int ); void slotLegacyBodyInvitesToggled( bool on ); private: virtual void doLoadFromGlobalSettings(); private: QCheckBox* mEnableGwCB; QCheckBox* mEnableImapResCB; QWidget* mBox; QVBox* gBox; QComboBox* mStorageFormatCombo; QComboBox* mLanguageCombo; QLabel* mFolderComboLabel; QWidgetStack* mFolderComboStack; KMail::FolderRequester* mFolderCombo; // in the widgetstack KMail::AccountComboBox* mAccountCombo; // in the widgetstack QCheckBox* mHideGroupwareFolders; QCheckBox* mOnlyShowGroupwareFolders; QCheckBox* mSyncImmediately; QCheckBox* mDeleteInvitations; QCheckBox* mLegacyMangleFromTo; QCheckBox* mLegacyBodyInvites; QCheckBox* mExchangeCompatibleInvitations; QCheckBox* mAutomaticSending; }; class KDE_EXPORT MiscPage : public ConfigModuleWithTabs { Q_OBJECT public: MiscPage( QWidget * parent=0, const char * name=0 ); QString helpAnchor() const; typedef MiscPageFolderTab FolderTab; typedef MiscPageGroupwareTab GroupwareTab; private: FolderTab * mFolderTab; GroupwareTab * mGroupwareTab; }; // // // further helper classes: // // class ListView : public KListView { Q_OBJECT public: ListView( QWidget *parent=0, const char *name=0, int visibleItem=10 ); void resizeColums(); void setVisibleItem( int visibleItem, bool updateSize=true ); virtual QSize sizeHint() const; protected: virtual void resizeEvent( QResizeEvent *e ); virtual void showEvent( QShowEvent *e ); private: int mVisibleItem; }; #endif // _CONFIGURE_DIALOG_PRIVATE_H_ diff --git a/kmail/recipientseditor.cpp b/kmail/recipientseditor.cpp index b2e7b14066..ddd5d4e0c8 100644 --- a/kmail/recipientseditor.cpp +++ b/kmail/recipientseditor.cpp @@ -1,1025 +1,1120 @@ /* This file is part of KMail. Copyright (c) 2004 Cornelius Schumacher This program 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. This program 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "recipientseditor.h" #include "recipientspicker.h" #include "kwindowpositioner.h" #include "distributionlistdialog.h" #include "globalsettings.h" #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include +#include #include #include +#include + +static QMutex s_locateListMutex; +static QStringList s_locatedKeys; + +void RecipientsLocateThread::run() +{ + gpgme_ctx_t ctx; + + // Make sure gpgme is initialized + gpgme_check_version( NULL ); + gpgme_error_t err = gpgme_new( &ctx ); + + if (err) + { + kdDebug( 5006 ) << "Failed to create context" << endl; + emit finished(); + return; + } + + // Setup the keylist + gpgme_set_protocol( ctx, GPGME_PROTOCOL_OpenPGP ); + gpgme_set_keylist_mode( ctx, GPGME_KEYLIST_MODE_EXTERN | + GPGME_KEYLIST_MODE_LOCAL ); + + err = gpgme_op_keylist_start( ctx, mAddr.utf8(), false ); + if ( err ) + { + kdDebug( 5006 ) << "Failed to start keylist" << endl; + gpgme_release( ctx ); + emit finished(); + return; + } + + gpgme_key_t key; + while (!( err = gpgme_op_keylist_next ( ctx, &key ) ) ) { + if ( !key ) { + continue; + } + kdDebug( 5006 ) << "Located key " << ( key->fpr ? key->fpr : "null" ) << endl; + gpgme_key_unref (key); + } + + gpgme_release( ctx ); + + emit finished(); +} + +void RecipientsLocateThread::setAddr(const QString &addr) +{ + mAddr = addr; +} + +RecipientsLocateThread::~RecipientsLocateThread() +{ + kdDebug( 5006 ) << "Keylocate of " << mAddr << " finished" << endl; +} + +static void locatePGPKey( const QString &email ) +{ + QMutexLocker lock ( &s_locateListMutex ); + + // Normalize mail + char *normalized = gpgme_addrspec_from_uid( email.utf8() ); + if ( !normalized ) { + kdDebug( 5006 ) << "Failed to normalize: " << email << endl; + return; + } + QString normStr( normalized ); + gpgme_free( normalized ); + if ( s_locatedKeys.findIndex( normStr ) != -1 ) { + return; + } + + RecipientsLocateThread *thread = new RecipientsLocateThread; + thread->setAddr( normStr ); + thread->start(); + + QObject::connect (thread, SIGNAL( finished() ), thread, SLOT( deleteLater() )); + s_locatedKeys.append( normStr ); +} + Recipient::Recipient( const QString &email, Recipient::Type type ) : mEmail( email ), mType( type ) { } void Recipient::setType( Type type ) { mType = type; } Recipient::Type Recipient::type() const { return mType; } void Recipient::setEmail( const QString &email ) { mEmail = email; } QString Recipient::email() const { return mEmail; } bool Recipient::isEmpty() const { return mEmail.isEmpty(); } int Recipient::typeToId( Recipient::Type type ) { return static_cast( type ); } Recipient::Type Recipient::idToType( int id ) { return static_cast( id ); } QString Recipient::typeLabel() const { return typeLabel( mType ); } QString Recipient::typeLabel( Recipient::Type type ) { switch( type ) { case To: return i18n("To"); case Cc: return i18n("CC"); case Bcc: return i18n("BCC"); case Undefined: break; } return i18n(""); } QStringList Recipient::allTypeLabels() { QStringList types; types.append( typeLabel( To ) ); types.append( typeLabel( Cc ) ); types.append( typeLabel( Bcc ) ); return types; } RecipientComboBox::RecipientComboBox( QWidget *parent ) : QComboBox( parent ) { } void RecipientComboBox::keyPressEvent( QKeyEvent *ev ) { if ( ev->key() == Key_Right ) emit rightPressed(); else QComboBox::keyPressEvent( ev ); } void RecipientLineEdit::keyPressEvent( QKeyEvent *ev ) { if ( ev->key() == Key_Backspace && text().isEmpty() ) { ev->accept(); emit deleteMe(); } else if ( ev->key() == Key_Left && cursorPosition() == 0 ) { emit leftPressed(); } else if ( ev->key() == Key_Right && cursorPosition() == (int)text().length() ) { emit rightPressed(); } else { KMLineEdit::keyPressEvent( ev ); } } RecipientLine::RecipientLine( QWidget *parent ) : QWidget( parent ), mRecipientsCount( 0 ), mModified( false ) { QBoxLayout *topLayout = new QHBoxLayout( this ); topLayout->setSpacing( KDialog::spacingHint() ); QStringList recipientTypes = Recipient::allTypeLabels(); mCombo = new RecipientComboBox( this ); mCombo->insertStringList( recipientTypes ); topLayout->addWidget( mCombo ); QToolTip::add( mCombo, i18n("Select type of recipient") ); mEdit = new RecipientLineEdit( this ); QToolTip::add( mEdit, i18n( "Set the list of email addresses to receive this message" ) ); topLayout->addWidget( mEdit ); connect( mEdit, SIGNAL( returnPressed() ), SLOT( slotReturnPressed() ) ); connect( mEdit, SIGNAL( deleteMe() ), SLOT( slotPropagateDeletion() ) ); connect( mEdit, SIGNAL( textChanged( const QString & ) ), SLOT( analyzeLine( const QString & ) ) ); connect( mEdit, SIGNAL( focusUp() ), SLOT( slotFocusUp() ) ); connect( mEdit, SIGNAL( focusDown() ), SLOT( slotFocusDown() ) ); connect( mEdit, SIGNAL( rightPressed() ), SIGNAL( rightPressed() ) ); connect( mEdit, SIGNAL( leftPressed() ), mCombo, SLOT( setFocus() ) ); connect( mCombo, SIGNAL( rightPressed() ), mEdit, SLOT( setFocus() ) ); connect( mCombo, SIGNAL( activated ( int ) ), this, SLOT( slotTypeModified() ) ); mRemoveButton = new QPushButton( this ); mRemoveButton->setIconSet( KApplication::reverseLayout() ? SmallIconSet("locationbar_erase") : SmallIconSet( "clear_left" ) ); topLayout->addWidget( mRemoveButton ); connect( mRemoveButton, SIGNAL( clicked() ), SLOT( slotPropagateDeletion() ) ); QToolTip::add( mRemoveButton, i18n("Remove recipient line") ); + + const KConfigGroup reader( KMKernel::config(), "Reader" ); + mDoKeyLocate = reader.readBoolEntry( "LocateKeys", true ); } void RecipientLine::slotFocusUp() { emit upPressed( this ); } void RecipientLine::slotFocusDown() { emit downPressed( this ); } void RecipientLine::slotTypeModified() { mModified = true; emit typeModified( this ); } void RecipientLine::analyzeLine( const QString &text ) { QStringList r = KPIM::splitEmailAddrList( text ); if ( int( r.count() ) != mRecipientsCount ) { mRecipientsCount = r.count(); emit countChanged(); } + + if ( mDoKeyLocate ) + { + for ( QStringList::ConstIterator it = r.constBegin(); it != r.constEnd(); ++it ) + { + locatePGPKey( *it ); + } + } } int RecipientLine::recipientsCount() { return mRecipientsCount; } void RecipientLine::setRecipient( const Recipient &rec ) { mEdit->setText( rec.email() ); mCombo->setCurrentItem( Recipient::typeToId( rec.type() ) ); } void RecipientLine::setRecipient( const QString &email ) { setRecipient( Recipient( email ) ); } Recipient RecipientLine::recipient() const { return Recipient( mEdit->text(), Recipient::idToType( mCombo->currentItem() ) ); } void RecipientLine::setRecipientType( Recipient::Type type ) { mCombo->setCurrentItem( Recipient::typeToId( type ) ); } Recipient::Type RecipientLine::recipientType() const { return Recipient::idToType( mCombo->currentItem() ); } void RecipientLine::activate() { mEdit->setFocus(); } bool RecipientLine::isActive() { return mEdit->hasFocus(); } bool RecipientLine::isEmpty() { return mEdit->text().isEmpty(); } bool RecipientLine::isModified() { return mModified || mEdit->isModified(); } void RecipientLine::clearModified() { mModified = false; mEdit->clearModified(); } void RecipientLine::slotReturnPressed() { emit returnPressed( this ); } void RecipientLine::slotPropagateDeletion() { emit deleteLine( this ); } void RecipientLine::keyPressEvent( QKeyEvent *ev ) { if ( ev->key() == Key_Up ) { emit upPressed( this ); } else if ( ev->key() == Key_Down ) { emit downPressed( this ); } } int RecipientLine::setComboWidth( int w ) { w = QMAX( w, mCombo->sizeHint().width() ); mCombo->setFixedWidth( w ); mCombo->updateGeometry(); parentWidget()->updateGeometry(); return w; } void RecipientLine::fixTabOrder( QWidget *previous ) { setTabOrder( previous, mCombo ); setTabOrder( mCombo, mEdit ); setTabOrder( mEdit, mRemoveButton ); } QWidget *RecipientLine::tabOut() const { return mRemoveButton; } void RecipientLine::clear() { mEdit->clear(); } void RecipientLine::setRemoveLineButtonEnabled( bool b ) { mRemoveButton->setEnabled( b ); } // ------------ RecipientsView --------------------- RecipientsView::RecipientsView( QWidget *parent ) : QScrollView( parent ), mCurDelLine( 0 ), mLineHeight( 0 ), mFirstColumnWidth( 0 ), mModified( false ), mLastMovedLine( NULL ) { mCompletionMode = KGlobalSettings::completionMode(); setHScrollBarMode( AlwaysOff ); setLineWidth( 0 ); addLine(); setResizePolicy( QScrollView::Manual ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); viewport()->setPaletteBackgroundColor( paletteBackgroundColor() ); } RecipientLine *RecipientsView::activeLine() { return mLines.last(); } RecipientLine *RecipientsView::emptyLine() { RecipientLine *line; for( line = mLines.first(); line; line = mLines.next() ) { if ( line->isEmpty() ) return line; } return 0; } RecipientLine *RecipientsView::addLine() { RecipientLine *line = new RecipientLine( viewport() ); addChild( line, 0, mLines.count() * mLineHeight ); line->mEdit->setCompletionMode( mCompletionMode ); line->show(); connect( line, SIGNAL( returnPressed( RecipientLine * ) ), SLOT( slotReturnPressed( RecipientLine * ) ) ); connect( line, SIGNAL( upPressed( RecipientLine * ) ), SLOT( slotUpPressed( RecipientLine * ) ) ); connect( line, SIGNAL( downPressed( RecipientLine * ) ), SLOT( slotDownPressed( RecipientLine * ) ) ); connect( line, SIGNAL( rightPressed() ), SIGNAL( focusRight() ) ); connect( line, SIGNAL( deleteLine( RecipientLine * ) ), SLOT( slotDecideLineDeletion( RecipientLine * ) ) ); connect( line, SIGNAL( countChanged() ), SLOT( calculateTotal() ) ); connect( line, SIGNAL( typeModified( RecipientLine * ) ), SLOT( slotTypeModified( RecipientLine * ) ) ); connect( line->mEdit, SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ), SLOT( setCompletionMode( KGlobalSettings::Completion ) ) ); if ( mLines.last() ) { if ( mLines.count() == 1 ) { if ( GlobalSettings::self()->secondRecipientTypeDefault() == GlobalSettings::EnumSecondRecipientTypeDefault::To ) { line->setRecipientType( Recipient::To ); } else { if ( mLines.last()->recipientType() == Recipient::Bcc ) { line->setRecipientType( Recipient::To ); } else { line->setRecipientType( Recipient::Cc ); } } } else { line->setRecipientType( mLines.last()->recipientType() ); } line->fixTabOrder( mLines.last()->tabOut() ); } mLines.append( line ); // If there is only one line, removing it makes no sense if ( mLines.count() == 1 ) { mLines.first()->setRemoveLineButtonEnabled( false ); } else { mLines.first()->setRemoveLineButtonEnabled( true ); } mFirstColumnWidth = line->setComboWidth( mFirstColumnWidth ); mLineHeight = line->minimumSizeHint().height(); line->resize( viewport()->width(), mLineHeight ); resizeView(); calculateTotal(); ensureVisible( 0, mLines.count() * mLineHeight ); return line; } void RecipientsView::slotTypeModified( RecipientLine *line ) { if ( mLines.count() == 2 || ( mLines.count() == 3 && mLines.at( 2 )->isEmpty() ) ) { if ( mLines.at( 1 ) == line ) { if ( line->recipientType() == Recipient::To ) { GlobalSettings::self()->setSecondRecipientTypeDefault( GlobalSettings::EnumSecondRecipientTypeDefault::To ); } else if ( line->recipientType() == Recipient::Cc ) { GlobalSettings::self()->setSecondRecipientTypeDefault( GlobalSettings::EnumSecondRecipientTypeDefault::Cc ); } } } } void RecipientsView::calculateTotal() { int count = 0; int empty = 0; RecipientLine *line; for( line = mLines.first(); line; line = mLines.next() ) { if ( line->isEmpty() ) ++empty; else count += line->recipientsCount(); } if ( empty == 0 ) addLine(); emit totalChanged( count, mLines.count() ); } void RecipientsView::slotReturnPressed( RecipientLine *line ) { if ( !line->recipient().isEmpty() ) { RecipientLine *empty = emptyLine(); if ( !empty ) empty = addLine(); activateLine( empty ); } } void RecipientsView::slotDownPressed( RecipientLine *line ) { int pos = mLines.find( line ); if ( pos >= (int)mLines.count() - 1 ) { emit focusDown(); } else if ( pos >= 0 ) { activateLine( mLines.at( pos + 1 ) ); } } void RecipientsView::slotUpPressed( RecipientLine *line ) { int pos = mLines.find( line ); if ( pos > 0 ) { activateLine( mLines.at( pos - 1 ) ); } else { emit focusUp(); } } void RecipientsView::slotDecideLineDeletion( RecipientLine *line ) { if ( !line->isEmpty() ) mModified = true; if ( mLines.count() == 1 ) { line->clear(); } else { mCurDelLine = line; QTimer::singleShot( 0, this, SLOT( slotDeleteLine( ) ) ); } } void RecipientsView::slotDeleteLine() { if ( !mCurDelLine ) return; RecipientLine *line = mCurDelLine; int pos = mLines.find( line ); int newPos; if ( pos == 0 ) newPos = pos + 1; else newPos = pos - 1; // if there is something left to activate, do so if ( mLines.at( newPos ) ) mLines.at( newPos )->activate(); mLines.remove( line ); removeChild( line ); delete line; bool atLeastOneToLine = false; unsigned int firstCC = 0; for( uint i = pos; i < mLines.count(); ++i ) { RecipientLine *line = mLines.at( i ); moveChild( line, childX( line ), childY( line ) - mLineHeight ); if ( line->recipientType() == Recipient::To ) atLeastOneToLine = true; else if ( ( line->recipientType() == Recipient::Cc ) && ( i == 0 ) ) firstCC = i; } // only one left, can't remove that one if ( mLines.count() == 1 ) mLines.first()->setRemoveLineButtonEnabled( false ); if ( !atLeastOneToLine ) mLines.at( firstCC )->setRecipientType( Recipient::To ); calculateTotal(); resizeView(); } void RecipientsView::resizeView() { resizeContents( width(), mLines.count() * mLineHeight ); if ( mLines.count() < 6 ) { // setFixedHeight( mLineHeight * mLines.count() ); } parentWidget()->layout()->activate(); emit sizeHintChanged(); QTimer::singleShot( 0, this, SLOT(moveCompletionPopup()) ); } void RecipientsView::activateLine( RecipientLine *line ) { line->activate(); ensureVisible( 0, childY( line ) ); } void RecipientsView::viewportResizeEvent ( QResizeEvent *ev ) { for( uint i = 0; i < mLines.count(); ++i ) { mLines.at( i )->resize( ev->size().width(), mLineHeight ); } ensureVisible( 0, mLines.count() * mLineHeight ); } QSize RecipientsView::sizeHint() const { return QSize( 200, mLineHeight * mLines.count() ); } QSize RecipientsView::minimumSizeHint() const { int height; uint numLines = 5; if ( mLines.count() < numLines ) height = mLineHeight * mLines.count(); else height = mLineHeight * numLines; return QSize( 200, height ); } Recipient::List RecipientsView::recipients() const { Recipient::List recipients; QPtrListIterator it( mLines ); RecipientLine *line; while( ( line = it.current() ) ) { if ( !line->recipient().isEmpty() ) { recipients.append( line->recipient() ); } ++it; } return recipients; } void RecipientsView::setCompletionMode ( KGlobalSettings::Completion mode ) { if ( mCompletionMode == mode ) return; mCompletionMode = mode; QPtrListIterator it( mLines ); RecipientLine *line; while( ( line = it.current() ) ) { line->mEdit->blockSignals( true ); line->mEdit->setCompletionMode( mode ); line->mEdit->blockSignals( false ); ++it; } emit completionModeChanged( mode ); //report change to RecipientsEditor } void RecipientsView::removeRecipient( const QString & recipient, Recipient::Type type ) { // search a line which matches recipient and type QPtrListIterator it( mLines ); RecipientLine *line; while( ( line = it.current() ) ) { if ( ( line->recipient().email() == recipient ) && ( line->recipientType() == type ) ) { break; } ++it; } if ( line ) line->slotPropagateDeletion(); } bool RecipientsView::isModified() { if ( mModified ) return true; QPtrListIterator it( mLines ); RecipientLine *line; while( ( line = it.current() ) ) { if ( line->isModified() ) { return true; } ++it; } return false; } void RecipientsView::clearModified() { mModified = false; QPtrListIterator it( mLines ); RecipientLine *line; while( ( line = it.current() ) ) { line->clearModified(); ++it; } } void RecipientsView::setFocus() { if ( mLines.last()->isActive() ) setFocusBottom(); else setFocusTop(); } void RecipientsView::setFocusTop() { RecipientLine *line = mLines.first(); if ( line ) line->activate(); else kdWarning() << "No first" << endl; } void RecipientsView::setFocusBottom() { RecipientLine *line = mLines.last(); if ( line ) line->activate(); else kdWarning() << "No last" << endl; } int RecipientsView::setFirstColumnWidth( int w ) { mFirstColumnWidth = w; QPtrListIterator it( mLines ); RecipientLine *line; while( ( line = it.current() ) ) { mFirstColumnWidth = line->setComboWidth( mFirstColumnWidth ); ++it; } resizeView(); return mFirstColumnWidth; } void RecipientsView::moveCompletionBottom() { if ( !mLastMovedLine ) { return; } mLastMovedLine->lineEdit()->completionBox()->show(); } void RecipientsView::moveCompletionPopup() { mLastMovedLine = NULL; for( RecipientLine* line = mLines.first(); line; line = mLines.next() ) { if ( line->lineEdit()->completionBox( false ) ) { if ( line->lineEdit()->completionBox()->isVisible() ) { // ### trigger moving, is there a nicer way to do that? // // ^ Original comment from back when. // Aheinecke 2018-03-12: // We had a hide and the show immediately afterwards here. // // This somehow caused problems with KWin or some other component // in Debian Stretch. // It caused the completionBox to be hidden behind the // MessageComposer. // // Hiding and then delaying the show by 500ms in moveCompletionBottom // seems to work nicely though. An immediate single Shot did not work. // // A don't ask me why but it works fix. line->lineEdit()->completionBox()->hide(); mLastMovedLine = line; } } } QTimer::singleShot( 500, this, SLOT( moveCompletionBottom( ) ) ); return; } RecipientsToolTip::RecipientsToolTip( RecipientsView *view, QWidget *parent ) : QToolTip( parent ), mView( view ) { } QString RecipientsToolTip::line( const Recipient &r ) { QString txt = r.email(); return "  " + QStyleSheet::escape( txt ) + "
"; } void RecipientsToolTip::maybeTip( const QPoint & p ) { QString text = ""; QString to; QString cc; QString bcc; Recipient::List recipients = mView->recipients(); Recipient::List::ConstIterator it; for( it = recipients.begin(); it != recipients.end(); ++it ) { switch( (*it).type() ) { case Recipient::To: to += line( *it ); break; case Recipient::Cc: cc += line( *it ); break; case Recipient::Bcc: bcc += line( *it ); break; default: break; } } text += i18n("To:
") + to; if ( !cc.isEmpty() ) text += i18n("CC:
") + cc; if ( !bcc.isEmpty() ) text += i18n("BCC:
") + bcc; text.append( "
" ); QRect geometry( p + QPoint( 2, 2 ), QPoint( 400, 100 ) ); tip( QRect( p.x() - 20, p.y() - 20, 40, 40 ), text, geometry ); } SideWidget::SideWidget( RecipientsView *view, QWidget *parent ) : QWidget( parent ), mView( view ), mRecipientPicker( 0 ) { QBoxLayout *topLayout = new QVBoxLayout( this ); topLayout->setSpacing( KDialog::spacingHint() ); topLayout->addStretch( 1 ); mTotalLabel = new QLabel( this ); mTotalLabel->setAlignment( AlignCenter ); topLayout->addWidget( mTotalLabel ); mTotalLabel->hide(); topLayout->addStretch( 1 ); new RecipientsToolTip( view, mTotalLabel ); mDistributionListButton = new QPushButton( i18n("Save List..."), this ); topLayout->addWidget( mDistributionListButton ); mDistributionListButton->hide(); connect( mDistributionListButton, SIGNAL( clicked() ), SIGNAL( saveDistributionList() ) ); QToolTip::add( mDistributionListButton, i18n("Save recipients as distribution list") ); mSelectButton = new QPushButton( i18n("Se&lect..."), this ); topLayout->addWidget( mSelectButton ); connect( mSelectButton, SIGNAL( clicked() ), SLOT( pickRecipient() ) ); QToolTip::add( mSelectButton, i18n("Select recipients from address book") ); } SideWidget::~SideWidget() { } RecipientsPicker* SideWidget::picker() const { if ( !mRecipientPicker ) { // hacks to allow picker() to be const in the presence of lazy loading SideWidget *non_const_this = const_cast( this ); mRecipientPicker = new RecipientsPicker( non_const_this ); connect( mRecipientPicker, SIGNAL( pickedRecipient( const Recipient & ) ), non_const_this, SIGNAL( pickedRecipient( const Recipient & ) ) ); mPickerPositioner = new KWindowPositioner( non_const_this, mRecipientPicker ); } return mRecipientPicker; } void SideWidget::setFocus() { mSelectButton->setFocus(); } void SideWidget::setTotal( int recipients, int lines ) { #if 0 kdDebug() << "SideWidget::setTotal() recipients: " << recipients << " lines: " << lines << endl; #endif QString labelText; if ( recipients == 0 ) labelText = i18n("No recipients"); else labelText = i18n("1 recipient","%n recipients", recipients ); mTotalLabel->setText( labelText ); if ( lines > 3 ) mTotalLabel->show(); else mTotalLabel->hide(); if ( lines > 2 ) mDistributionListButton->show(); else mDistributionListButton->hide(); } void SideWidget::pickRecipient() { #if 0 QString rec = KInputDialog::getText( "Pick Recipient", "Email address of recipient" ); if ( !rec.isEmpty() ) emit pickedRecipient( rec ); #else RecipientsPicker *p = picker(); p->setDefaultType( mView->activeLine()->recipientType() ); p->setRecipients( mView->recipients() ); p->show(); mPickerPositioner->reposition(); p->raise(); #endif } RecipientsEditor::RecipientsEditor( QWidget *parent ) : QWidget( parent ), mModified( false ) { QBoxLayout *topLayout = new QHBoxLayout( this ); topLayout->setSpacing( KDialog::spacingHint() ); mRecipientsView = new RecipientsView( this ); topLayout->addWidget( mRecipientsView ); connect( mRecipientsView, SIGNAL( focusUp() ), SIGNAL( focusUp() ) ); connect( mRecipientsView, SIGNAL( focusDown() ), SIGNAL( focusDown() ) ); connect( mRecipientsView, SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ), SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ) ); mSideWidget = new SideWidget( mRecipientsView, this ); topLayout->addWidget( mSideWidget ); connect( mSideWidget, SIGNAL( pickedRecipient( const Recipient & ) ), SLOT( slotPickedRecipient( const Recipient & ) ) ); connect( mSideWidget, SIGNAL( saveDistributionList() ), SLOT( saveDistributionList() ) ); connect( mRecipientsView, SIGNAL( totalChanged( int, int ) ), mSideWidget, SLOT( setTotal( int, int ) ) ); connect( mRecipientsView, SIGNAL( focusRight() ), mSideWidget, SLOT( setFocus() ) ); connect( mRecipientsView, SIGNAL(sizeHintChanged()), SIGNAL(sizeHintChanged()) ); } RecipientsEditor::~RecipientsEditor() { } RecipientsPicker* RecipientsEditor::picker() const { return mSideWidget->picker(); } void RecipientsEditor::slotPickedRecipient( const Recipient &rec ) { RecipientLine *line = mRecipientsView->activeLine(); if ( !line->isEmpty() ) line = mRecipientsView->addLine(); Recipient r = rec; if ( r.type() == Recipient::Undefined ) { r.setType( line->recipientType() ); } line->setRecipient( r ); mModified = true; } void RecipientsEditor::saveDistributionList() { DistributionListDialog *dlg = new DistributionListDialog( this ); dlg->setRecipients( mRecipientsView->recipients() ); dlg->exec(); delete dlg; } Recipient::List RecipientsEditor::recipients() const { return mRecipientsView->recipients(); } void RecipientsEditor::setRecipientString( const QString &str, Recipient::Type type ) { clear(); int count = 1; QStringList r = KPIM::splitEmailAddrList( str ); QStringList::ConstIterator it; for( it = r.begin(); it != r.end(); ++it ) { if ( count++ > GlobalSettings::self()->maximumRecipients() ) { KMessageBox::sorry( this, i18n("Truncating recipients list to %1 of %2 entries.") .arg( GlobalSettings::self()->maximumRecipients() ) .arg( r.count() ) ); break; } addRecipient( *it, type ); } } QString RecipientsEditor::recipientString( Recipient::Type type ) { QString str; Recipient::List recipients = mRecipientsView->recipients(); Recipient::List::ConstIterator it; for( it = recipients.begin(); it != recipients.end(); ++it ) { if ( (*it).type() == type ) { if ( !str.isEmpty() ) str += ", "; str.append( (*it).email() ); } } return str; } void RecipientsEditor::addRecipient( const QString & recipient, Recipient::Type type ) { RecipientLine *line = mRecipientsView->emptyLine(); if ( !line ) line = mRecipientsView->addLine(); line->setRecipient( Recipient( recipient, type ) ); } void RecipientsEditor::removeRecipient( const QString & recipient, Recipient::Type type ) { mRecipientsView->removeRecipient( recipient, type ); } bool RecipientsEditor::isModified() { return mModified || mRecipientsView->isModified(); } void RecipientsEditor::clearModified() { mModified = false; mRecipientsView->clearModified(); } void RecipientsEditor::clear() { } void RecipientsEditor::setFocus() { mRecipientsView->setFocus(); } void RecipientsEditor::setFocusTop() { mRecipientsView->setFocusTop(); } void RecipientsEditor::setFocusBottom() { mRecipientsView->setFocusBottom(); } int RecipientsEditor::setFirstColumnWidth( int w ) { return mRecipientsView->setFirstColumnWidth( w ); } void RecipientsEditor::selectRecipients() { mSideWidget->pickRecipient(); } void RecipientsEditor::setCompletionMode( KGlobalSettings::Completion mode ) { mRecipientsView->setCompletionMode( mode ); } #include "recipientseditor.moc" diff --git a/kmail/recipientseditor.h b/kmail/recipientseditor.h index 1e6c7805fa..3292905951 100644 --- a/kmail/recipientseditor.h +++ b/kmail/recipientseditor.h @@ -1,368 +1,387 @@ /* This file is part of KMail. Copyright (c) 2004 Cornelius Schumacher This program 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. This program 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #ifndef RECIPIENTSEDITOR_H #define RECIPIENTSEDITOR_H #include #include #include #include #include +#include #include "kmlineeditspell.h" #include class RecipientsPicker; class KWindowPositioner; class QLabel; class QPushButton; class SideWidget; class Recipient { public: typedef QValueList List; enum Type { To, Cc, Bcc, Undefined }; Recipient( const QString &email = QString::null, Type type = To ); void setType( Type ); Type type() const; void setEmail( const QString & ); QString email() const; bool isEmpty() const; static int typeToId( Type ); static Type idToType( int ); QString typeLabel() const; static QString typeLabel( Type ); static QStringList allTypeLabels(); private: QString mEmail; Type mType; }; class RecipientComboBox : public QComboBox { Q_OBJECT public: RecipientComboBox( QWidget *parent ); signals: void rightPressed(); protected: void keyPressEvent( QKeyEvent *ev ); }; class RecipientLineEdit : public KMLineEdit { Q_OBJECT public: RecipientLineEdit( QWidget * parent ) : KMLineEdit( true, parent ) {} signals: void deleteMe(); void leftPressed(); void rightPressed(); protected: void keyPressEvent( QKeyEvent *ev ); }; class RecipientLine : public QWidget { Q_OBJECT public: RecipientLine( QWidget *parent ); void setRecipient( const Recipient & ); Recipient recipient() const; void setRecipientType( Recipient::Type ); Recipient::Type recipientType() const; void setRecipient( const QString & ); void activate(); bool isActive(); bool isEmpty(); /** Returns true if the user has made any modifications to this RecipientLine. */ bool isModified(); /** Resets the modified flag to false. */ void clearModified(); int setComboWidth( int w ); void fixTabOrder( QWidget *previous ); QWidget *tabOut() const; void clear(); int recipientsCount(); void setRemoveLineButtonEnabled( bool b ); signals: void returnPressed( RecipientLine * ); void downPressed( RecipientLine * ); void upPressed( RecipientLine * ); void rightPressed(); void deleteLine( RecipientLine * ); void countChanged(); void typeModified( RecipientLine * ); protected: void keyPressEvent( QKeyEvent * ); RecipientLineEdit* lineEdit() const { return mEdit; } protected slots: void slotReturnPressed(); void analyzeLine( const QString & ); void slotFocusUp(); void slotFocusDown(); void slotPropagateDeletion(); void slotTypeModified(); private: friend class RecipientsView; QComboBox *mCombo; RecipientLineEdit *mEdit; QPushButton *mRemoveButton; int mRecipientsCount; bool mModified; + bool mDoKeyLocate; }; class RecipientsView : public QScrollView { Q_OBJECT public: RecipientsView( QWidget *parent ); QSize minimumSizeHint() const; QSize sizeHint() const; RecipientLine *activeLine(); RecipientLine *emptyLine(); Recipient::List recipients() const; /** Removes the recipient provided it can be found and has the given type. @param recipient The recipient(s) you want to remove. @param type The recipient type. */ void removeRecipient( const QString & recipient, Recipient::Type type ); /** Returns true if the user has made any modifications to the list of recipients. */ bool isModified(); /** Resets the modified flag to false. */ void clearModified(); void activateLine( RecipientLine * ); /** * Set the width of the left most column to be the argument width. * This method allows other widgets to align their label/combobox column with ours * by communicating how many pixels that first colum is for them. * Returns the width that is actually being used. */ int setFirstColumnWidth( int ); public slots: void setCompletionMode( KGlobalSettings::Completion ); RecipientLine *addLine(); void setFocus(); void setFocusTop(); void setFocusBottom(); signals: void totalChanged( int recipients, int lines ); void focusUp(); void focusDown(); void focusRight(); void completionModeChanged( KGlobalSettings::Completion ); void sizeHintChanged(); protected: void viewportResizeEvent( QResizeEvent * ); void resizeView(); protected slots: void slotReturnPressed( RecipientLine * ); void slotDownPressed( RecipientLine * ); void slotUpPressed( RecipientLine * ); void slotDecideLineDeletion( RecipientLine * ); void slotDeleteLine(); void calculateTotal(); void slotTypeModified( RecipientLine * ); void moveCompletionPopup(); void moveCompletionBottom(); private: QPtrList mLines; QGuardedPtr mCurDelLine; int mLineHeight; int mFirstColumnWidth; bool mModified; RecipientLine *mLastMovedLine; KGlobalSettings::Completion mCompletionMode; }; class RecipientsToolTip : public QToolTip { public: RecipientsToolTip( RecipientsView *, QWidget *parent ); protected: void maybeTip( const QPoint & p ); QString line( const Recipient & ); private: RecipientsView *mView; }; class SideWidget : public QWidget { Q_OBJECT public: SideWidget( RecipientsView *view, QWidget *parent ); ~SideWidget(); RecipientsPicker* picker() const; public slots: void setTotal( int recipients, int lines ); void setFocus(); void pickRecipient(); signals: void pickedRecipient( const Recipient & ); void saveDistributionList(); private: RecipientsView *mView; QLabel *mTotalLabel; QPushButton *mDistributionListButton; QPushButton *mSelectButton; /** The RecipientsPicker is lazy loaded, never access it directly, only through picker() */ mutable RecipientsPicker *mRecipientPicker; /** lazy loaded, don't access directly, unless you've called picker() */ mutable KWindowPositioner *mPickerPositioner; }; class RecipientsEditor : public QWidget { Q_OBJECT public: RecipientsEditor( QWidget *parent ); ~RecipientsEditor(); void clear(); Recipient::List recipients() const; RecipientsPicker* picker() const; void setRecipientString( const QString &, Recipient::Type ); QString recipientString( Recipient::Type ); /** Adds a recipient (or multiple recipients) to one line of the editor. @param recipient The recipient(s) you want to add. @param type The recipient type. */ void addRecipient( const QString & recipient, Recipient::Type type ); /** Removes the recipient provided it can be found and has the given type. @param recipient The recipient(s) you want to remove. @param type The recipient type. */ void removeRecipient( const QString & recipient, Recipient::Type type ); /** Returns true if the user has made any modifications to the list of recipients. */ bool isModified(); /** Resets the modified flag to false. */ void clearModified(); /** * Set the width of the left most column to be the argument width. * This method allows other widgets to align their label/combobox column with ours * by communicating how many pixels that first colum is for them. * Returns the width that is actually being used. */ int setFirstColumnWidth( int ); /** * Set completion mode for all lines */ void setCompletionMode( KGlobalSettings::Completion ); public slots: void setFocus(); void setFocusTop(); void setFocusBottom(); void selectRecipients(); void saveDistributionList(); signals: void focusUp(); void focusDown(); void completionModeChanged( KGlobalSettings::Completion ); void sizeHintChanged(); protected slots: void slotPickedRecipient( const Recipient & ); private: RecipientsView *mRecipientsView; SideWidget* mSideWidget; bool mModified; }; +class RecipientsLocateThread : public QObject, public QThread +{ + Q_OBJECT + + public: + virtual void run(); + virtual ~RecipientsLocateThread(); + + void setAddr(const QString &addr); + + signals: + void finished(); + + private: + QString mAddr; +}; + #endif