kmail

configuredialog.cpp

00001 /*   -*- mode: C++; c-file-style: "gnu" -*-
00002  *   kmail: KDE mail client
00003  *   This file: Copyright (C) 2000 Espen Sand, espen@kde.org
00004  *              Copyright (C) 2001-2003 Marc Mutz, mutz@kde.org
00005  *   Contains code segments and ideas from earlier kmail dialog code.
00006  *
00007  *   This program is free software; you can redistribute it and/or modify
00008  *   it under the terms of the GNU General Public License as published by
00009  *   the Free Software Foundation; either version 2 of the License, or
00010  *   (at your option) any later version.
00011  *
00012  *   This program is distributed in the hope that it will be useful,
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *   GNU General Public License for more details.
00016  *
00017  *   You should have received a copy of the GNU General Public License
00018  *   along with this program; if not, write to the Free Software
00019  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 // This must be first
00024 #include <config.h>
00025 
00026 // my headers:
00027 #include "configuredialog.h"
00028 #include "configuredialog_p.h"
00029 
00030 #include "globalsettings.h"
00031 #include "replyphrases.h"
00032 #include "templatesconfiguration_kfg.h"
00033 
00034 // other KMail headers:
00035 #include "kmkernel.h"
00036 #include "simplestringlisteditor.h"
00037 #include "accountdialog.h"
00038 using KMail::AccountDialog;
00039 #include "colorlistbox.h"
00040 #include "kmacctseldlg.h"
00041 #include "messagesender.h"
00042 #include "kmtransport.h"
00043 #include "kmfoldermgr.h"
00044 #include <libkpimidentities/identitymanager.h>
00045 #include "identitylistview.h"
00046 using KMail::IdentityListView;
00047 using KMail::IdentityListViewItem;
00048 #include "kcursorsaver.h"
00049 #include "accountmanager.h"
00050 #include <composercryptoconfiguration.h>
00051 #include <warningconfiguration.h>
00052 #include <smimeconfiguration.h>
00053 #include "templatesconfiguration.h"
00054 #include "customtemplates.h"
00055 #include "folderrequester.h"
00056 using KMail::FolderRequester;
00057 #include "accountcombobox.h"
00058 #include "imapaccountbase.h"
00059 using KMail::ImapAccountBase;
00060 #include "folderstorage.h"
00061 #include "kmfolder.h"
00062 #include "kmmainwidget.h"
00063 #include "recentaddresses.h"
00064 using KRecentAddress::RecentAddresses;
00065 #include "completionordereditor.h"
00066 #include "ldapclient.h"
00067 #include "index.h"
00068 
00069 using KMail::IdentityListView;
00070 using KMail::IdentityListViewItem;
00071 #include "identitydialog.h"
00072 using KMail::IdentityDialog;
00073 
00074 // other kdenetwork headers:
00075 #include <libkpimidentities/identity.h>
00076 #include <kmime_util.h>
00077 using KMime::DateFormatter;
00078 #include <kleo/cryptoconfig.h>
00079 #include <kleo/cryptobackendfactory.h>
00080 #include <ui/backendconfigwidget.h>
00081 #include <ui/keyrequester.h>
00082 #include <ui/keyselectiondialog.h>
00083 
00084 // other KDE headers:
00085 #include <klocale.h>
00086 #include <kapplication.h>
00087 #include <kcharsets.h>
00088 #include <kasciistringtools.h>
00089 #include <kdebug.h>
00090 #include <knuminput.h>
00091 #include <kfontdialog.h>
00092 #include <kmessagebox.h>
00093 #include <kurlrequester.h>
00094 #include <kseparator.h>
00095 #include <kiconloader.h>
00096 #include <kstandarddirs.h>
00097 #include <kwin.h>
00098 #include <knotifydialog.h>
00099 #include <kconfig.h>
00100 #include <kactivelabel.h>
00101 #include <kcmultidialog.h>
00102 #include <kcombobox.h>
00103 
00104 // Qt headers:
00105 #include <qvalidator.h>
00106 #include <qwhatsthis.h>
00107 #include <qvgroupbox.h>
00108 #include <qvbox.h>
00109 #include <qvbuttongroup.h>
00110 #include <qhbuttongroup.h>
00111 #include <qtooltip.h>
00112 #include <qlabel.h>
00113 #include <qtextcodec.h>
00114 #include <qheader.h>
00115 #include <qpopupmenu.h>
00116 #include <qradiobutton.h>
00117 #include <qlayout.h>
00118 #include <qcheckbox.h>
00119 #include <qwidgetstack.h>
00120 
00121 // other headers:
00122 #include <assert.h>
00123 #include <stdlib.h>
00124 
00125 #ifndef _PATH_SENDMAIL
00126 #define _PATH_SENDMAIL  "/usr/sbin/sendmail"
00127 #endif
00128 
00129 #ifdef DIM
00130 #undef DIM
00131 #endif
00132 #define DIM(x) sizeof(x) / sizeof(*x)
00133 
00134 namespace {
00135 
00136   struct EnumConfigEntryItem {
00137     const char * key; // config key value, as appears in config file
00138     const char * desc; // description, to be i18n()ized
00139   };
00140   struct EnumConfigEntry {
00141     const char * group;
00142     const char * key;
00143     const char * desc;
00144     const EnumConfigEntryItem * items;
00145     int numItems;
00146     int defaultItem;
00147   };
00148   struct BoolConfigEntry {
00149     const char * group;
00150     const char * key;
00151     const char * desc;
00152     bool defaultValue;
00153   };
00154 
00155   static const char * lockedDownWarning =
00156     I18N_NOOP("<qt><p>This setting has been fixed by your administrator.</p>"
00157               "<p>If you think this is an error, please contact him.</p></qt>");
00158 
00159   void checkLockDown( QWidget * w, const KConfigBase & c, const char * key ) {
00160     if ( c.entryIsImmutable( key ) ) {
00161       w->setEnabled( false );
00162       QToolTip::add( w, i18n( lockedDownWarning ) );
00163     } else {
00164       QToolTip::remove( w );
00165     }
00166   }
00167 
00168   void populateButtonGroup( QButtonGroup * g, const EnumConfigEntry & e ) {
00169     g->setTitle( i18n( e.desc ) );
00170     g->layout()->setSpacing( KDialog::spacingHint() );
00171     for ( int i = 0 ; i < e.numItems ; ++i )
00172       g->insert( new QRadioButton( i18n( e.items[i].desc ), g ), i );
00173   }
00174 
00175   void populateCheckBox( QCheckBox * b, const BoolConfigEntry & e ) {
00176     b->setText( i18n( e.desc ) );
00177   }
00178 
00179   void loadWidget( QCheckBox * b, const KConfigBase & c, const BoolConfigEntry & e ) {
00180     Q_ASSERT( c.group() == e.group );
00181     checkLockDown( b, c, e.key );
00182     b->setChecked( c.readBoolEntry( e.key, e.defaultValue ) );
00183   }
00184 
00185   void loadWidget( QButtonGroup * g, const KConfigBase & c, const EnumConfigEntry & e ) {
00186     Q_ASSERT( c.group() == e.group );
00187     Q_ASSERT( g->count() == e.numItems );
00188     checkLockDown( g, c, e.key );
00189     const QString s = c.readEntry( e.key, e.items[e.defaultItem].key );
00190     for ( int i = 0 ; i < e.numItems ; ++i )
00191       if ( s == e.items[i].key ) {
00192         g->setButton( i );
00193         return;
00194       }
00195     g->setButton( e.defaultItem );
00196   }
00197 
00198   void saveCheckBox( QCheckBox * b, KConfigBase & c, const BoolConfigEntry & e ) {
00199     Q_ASSERT( c.group() == e.group );
00200     c.writeEntry( e.key, b->isChecked() );
00201   }
00202 
00203   void saveButtonGroup( QButtonGroup * g, KConfigBase & c, const EnumConfigEntry & e ) {
00204     Q_ASSERT( c.group() == e.group );
00205     Q_ASSERT( g->count() == e.numItems );
00206     c.writeEntry( e.key, e.items[ g->id( g->selected() ) ].key );
00207   }
00208 
00209   template <typename T_Widget, typename T_Entry>
00210   inline void loadProfile( T_Widget * g, const KConfigBase & c, const T_Entry & e ) {
00211     if ( c.hasKey( e.key ) )
00212       loadWidget( g, c, e );
00213   }
00214 }
00215 
00216 
00217 ConfigureDialog::ConfigureDialog( QWidget *parent, const char *name, bool modal )
00218   : KCMultiDialog( KDialogBase::IconList, KGuiItem( i18n( "&Load Profile..." ) ),
00219                    KGuiItem(), User2, i18n( "Configure" ), parent, name, modal )
00220   , mProfileDialog( 0 )
00221 {
00222   KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
00223   showButton( User1, true );
00224 
00225   addModule ( "kmail_config_identity", false );
00226   addModule ( "kmail_config_accounts", false );
00227   addModule ( "kmail_config_appearance", false );
00228   addModule ( "kmail_config_composer", false );
00229   addModule ( "kmail_config_security", false );
00230   addModule ( "kmail_config_misc", false );
00231 
00232   // We store the size of the dialog on hide, because otherwise
00233   // the KCMultiDialog starts with the size of the first kcm, not
00234   // the largest one. This way at least after the first showing of
00235   // the largest kcm the size is kept.
00236   KConfigGroup geometry( KMKernel::config(), "Geometry" );
00237   int width = geometry.readNumEntry( "ConfigureDialogWidth" );
00238   int height = geometry.readNumEntry( "ConfigureDialogHeight" );
00239   if ( width != 0 && height != 0 ) {
00240      setMinimumSize( width, height );
00241   }
00242 
00243 }
00244 
00245 void ConfigureDialog::hideEvent( QHideEvent *ev ) {
00246   KConfigGroup geometry( KMKernel::config(), "Geometry" );
00247   geometry.writeEntry( "ConfigureDialogWidth", width() );
00248   geometry.writeEntry( "ConfigureDialogHeight",height() );
00249   KDialogBase::hideEvent( ev );
00250 }
00251 
00252 ConfigureDialog::~ConfigureDialog() {
00253 }
00254 
00255 void ConfigureDialog::slotApply() {
00256   KCMultiDialog::slotApply();
00257   GlobalSettings::self()->writeConfig();
00258   emit configChanged();
00259 }
00260 
00261 void ConfigureDialog::slotOk() {
00262   KCMultiDialog::slotOk();
00263   GlobalSettings::self()->writeConfig();
00264   emit configChanged();
00265 }
00266 
00267 void ConfigureDialog::slotUser2() {
00268   if ( mProfileDialog ) {
00269     mProfileDialog->raise();
00270     return;
00271   }
00272   mProfileDialog = new ProfileDialog( this, "mProfileDialog" );
00273   connect( mProfileDialog, SIGNAL(profileSelected(KConfig*)),
00274                 this, SIGNAL(installProfile(KConfig*)) );
00275   mProfileDialog->show();
00276 }
00277 
00278 // *************************************************************
00279 // *                                                           *
00280 // *                      IdentityPage                         *
00281 // *                                                           *
00282 // *************************************************************
00283 QString IdentityPage::helpAnchor() const {
00284   return QString::fromLatin1("configure-identity");
00285 }
00286 
00287 IdentityPage::IdentityPage( QWidget * parent, const char * name )
00288   : ConfigModule( parent, name ),
00289     mIdentityDialog( 0 )
00290 {
00291   QHBoxLayout * hlay = new QHBoxLayout( this, 0, KDialog::spacingHint() );
00292 
00293   mIdentityList = new IdentityListView( this );
00294   connect( mIdentityList, SIGNAL(selectionChanged()),
00295            SLOT(slotIdentitySelectionChanged()) );
00296   connect( mIdentityList, SIGNAL(itemRenamed(QListViewItem*,const QString&,int)),
00297            SLOT(slotRenameIdentity(QListViewItem*,const QString&,int)) );
00298   connect( mIdentityList, SIGNAL(doubleClicked(QListViewItem*,const QPoint&,int)),
00299            SLOT(slotModifyIdentity()) );
00300   connect( mIdentityList, SIGNAL(contextMenu(KListView*,QListViewItem*,const QPoint&)),
00301            SLOT(slotContextMenu(KListView*,QListViewItem*,const QPoint&)) );
00302   // ### connect dragged(...), ...
00303 
00304   hlay->addWidget( mIdentityList, 1 );
00305 
00306   QVBoxLayout * vlay = new QVBoxLayout( hlay ); // inherits spacing
00307 
00308   QPushButton * button = new QPushButton( i18n("&Add..."), this );
00309   mModifyButton = new QPushButton( i18n("&Modify..."), this );
00310   mRenameButton = new QPushButton( i18n("&Rename"), this );
00311   mRemoveButton = new QPushButton( i18n("Remo&ve"), this );
00312   mSetAsDefaultButton = new QPushButton( i18n("Set as &Default"), this );
00313   button->setAutoDefault( false );
00314   mModifyButton->setAutoDefault( false );
00315   mModifyButton->setEnabled( false );
00316   mRenameButton->setAutoDefault( false );
00317   mRenameButton->setEnabled( false );
00318   mRemoveButton->setAutoDefault( false );
00319   mRemoveButton->setEnabled( false );
00320   mSetAsDefaultButton->setAutoDefault( false );
00321   mSetAsDefaultButton->setEnabled( false );
00322   connect( button, SIGNAL(clicked()),
00323            this, SLOT(slotNewIdentity()) );
00324   connect( mModifyButton, SIGNAL(clicked()),
00325            this, SLOT(slotModifyIdentity()) );
00326   connect( mRenameButton, SIGNAL(clicked()),
00327            this, SLOT(slotRenameIdentity()) );
00328   connect( mRemoveButton, SIGNAL(clicked()),
00329            this, SLOT(slotRemoveIdentity()) );
00330   connect( mSetAsDefaultButton, SIGNAL(clicked()),
00331            this, SLOT(slotSetAsDefault()) );
00332   vlay->addWidget( button );
00333   vlay->addWidget( mModifyButton );
00334   vlay->addWidget( mRenameButton );
00335   vlay->addWidget( mRemoveButton );
00336   vlay->addWidget( mSetAsDefaultButton );
00337   vlay->addStretch( 1 );
00338   load();
00339 }
00340 
00341 void IdentityPage::load()
00342 {
00343   KPIM::IdentityManager * im = kmkernel->identityManager();
00344   mOldNumberOfIdentities = im->shadowIdentities().count();
00345   // Fill the list:
00346   mIdentityList->clear();
00347   QListViewItem * item = 0;
00348   for ( KPIM::IdentityManager::Iterator it = im->modifyBegin() ; it != im->modifyEnd() ; ++it )
00349     item = new IdentityListViewItem( mIdentityList, item, *it  );
00350   mIdentityList->setSelected( mIdentityList->currentItem(), true );
00351 }
00352 
00353 void IdentityPage::save() {
00354   assert( !mIdentityDialog );
00355 
00356   kmkernel->identityManager()->sort();
00357   kmkernel->identityManager()->commit();
00358 
00359   if( mOldNumberOfIdentities < 2 && mIdentityList->childCount() > 1 ) {
00360     // have more than one identity, so better show the combo in the
00361     // composer now:
00362     KConfigGroup composer( KMKernel::config(), "Composer" );
00363     int showHeaders = composer.readNumEntry( "headers", HDR_STANDARD );
00364     showHeaders |= HDR_IDENTITY;
00365     composer.writeEntry( "headers", showHeaders );
00366   }
00367   // and now the reverse
00368   if( mOldNumberOfIdentities > 1 && mIdentityList->childCount() < 2 ) {
00369     // have only one identity, so remove the combo in the composer:
00370     KConfigGroup composer( KMKernel::config(), "Composer" );
00371     int showHeaders = composer.readNumEntry( "headers", HDR_STANDARD );
00372     showHeaders &= ~HDR_IDENTITY;
00373     composer.writeEntry( "headers", showHeaders );
00374   }
00375 }
00376 
00377 void IdentityPage::slotNewIdentity()
00378 {
00379   assert( !mIdentityDialog );
00380 
00381   KPIM::IdentityManager * im = kmkernel->identityManager();
00382   NewIdentityDialog dialog( im->shadowIdentities(), this, "new", true );
00383 
00384   if( dialog.exec() == QDialog::Accepted ) {
00385     QString identityName = dialog.identityName().stripWhiteSpace();
00386     assert( !identityName.isEmpty() );
00387 
00388     //
00389     // Construct a new Identity:
00390     //
00391     switch ( dialog.duplicateMode() ) {
00392     case NewIdentityDialog::ExistingEntry:
00393       {
00394         KPIM::Identity & dupThis = im->modifyIdentityForName( dialog.duplicateIdentity() );
00395         im->newFromExisting( dupThis, identityName );
00396         break;
00397       }
00398     case NewIdentityDialog::ControlCenter:
00399       im->newFromControlCenter( identityName );
00400       break;
00401     case NewIdentityDialog::Empty:
00402       im->newFromScratch( identityName );
00403     default: ;
00404     }
00405 
00406     //
00407     // Insert into listview:
00408     //
00409     KPIM::Identity & newIdent = im->modifyIdentityForName( identityName );
00410     QListViewItem * item = mIdentityList->selectedItem();
00411     if ( item )
00412       item = item->itemAbove();
00413     mIdentityList->setSelected( new IdentityListViewItem( mIdentityList,
00414                                                           /*after*/ item,
00415                                                           newIdent ), true );
00416     slotModifyIdentity();
00417   }
00418 }
00419 
00420 void IdentityPage::slotModifyIdentity() {
00421   assert( !mIdentityDialog );
00422 
00423   IdentityListViewItem * item =
00424     dynamic_cast<IdentityListViewItem*>( mIdentityList->selectedItem() );
00425   if ( !item ) return;
00426 
00427   mIdentityDialog = new IdentityDialog( this );
00428   mIdentityDialog->setIdentity( item->identity() );
00429 
00430   // Hmm, an unmodal dialog would be nicer, but a modal one is easier ;-)
00431   if ( mIdentityDialog->exec() == QDialog::Accepted ) {
00432     mIdentityDialog->updateIdentity( item->identity() );
00433     item->redisplay();
00434     emit changed(true);
00435   }
00436 
00437   delete mIdentityDialog;
00438   mIdentityDialog = 0;
00439 }
00440 
00441 void IdentityPage::slotRemoveIdentity()
00442 {
00443   assert( !mIdentityDialog );
00444 
00445   KPIM::IdentityManager * im = kmkernel->identityManager();
00446   kdFatal( im->shadowIdentities().count() < 2 )
00447     << "Attempted to remove the last identity!" << endl;
00448 
00449   IdentityListViewItem * item =
00450     dynamic_cast<IdentityListViewItem*>( mIdentityList->selectedItem() );
00451   if ( !item ) return;
00452 
00453   QString msg = i18n("<qt>Do you really want to remove the identity named "
00454                      "<b>%1</b>?</qt>").arg( item->identity().identityName() );
00455   if( KMessageBox::warningContinueCancel( this, msg, i18n("Remove Identity"),
00456    KGuiItem(i18n("&Remove"),"editdelete") ) == KMessageBox::Continue )
00457     if ( im->removeIdentity( item->identity().identityName() ) ) {
00458       delete item;
00459       mIdentityList->setSelected( mIdentityList->currentItem(), true );
00460       refreshList();
00461     }
00462 }
00463 
00464 void IdentityPage::slotRenameIdentity() {
00465   assert( !mIdentityDialog );
00466 
00467   QListViewItem * item = mIdentityList->selectedItem();
00468   if ( !item ) return;
00469 
00470   mIdentityList->rename( item, 0 );
00471 }
00472 
00473 void IdentityPage::slotRenameIdentity( QListViewItem * i,
00474                                        const QString & s, int col ) {
00475   assert( col == 0 );
00476   Q_UNUSED( col );
00477 
00478   IdentityListViewItem * item = dynamic_cast<IdentityListViewItem*>( i );
00479   if ( !item ) return;
00480 
00481   QString newName = s.stripWhiteSpace();
00482   if ( !newName.isEmpty() &&
00483        !kmkernel->identityManager()->shadowIdentities().contains( newName ) ) {
00484     KPIM::Identity & ident = item->identity();
00485     ident.setIdentityName( newName );
00486     emit changed(true);
00487   }
00488   item->redisplay();
00489 }
00490 
00491 void IdentityPage::slotContextMenu( KListView *, QListViewItem * i,
00492                                     const QPoint & pos ) {
00493   IdentityListViewItem * item = dynamic_cast<IdentityListViewItem*>( i );
00494 
00495   QPopupMenu * menu = new QPopupMenu( this );
00496   menu->insertItem( i18n("Add..."), this, SLOT(slotNewIdentity()) );
00497   if ( item ) {
00498     menu->insertItem( i18n("Modify..."), this, SLOT(slotModifyIdentity()) );
00499     if ( mIdentityList->childCount() > 1 )
00500       menu->insertItem( i18n("Remove"), this, SLOT(slotRemoveIdentity()) );
00501     if ( !item->identity().isDefault() )
00502       menu->insertItem( i18n("Set as Default"), this, SLOT(slotSetAsDefault()) );
00503   }
00504   menu->exec( pos );
00505   delete menu;
00506 }
00507 
00508 
00509 void IdentityPage::slotSetAsDefault() {
00510   assert( !mIdentityDialog );
00511 
00512   IdentityListViewItem * item =
00513     dynamic_cast<IdentityListViewItem*>( mIdentityList->selectedItem() );
00514   if ( !item ) return;
00515 
00516   KPIM::IdentityManager * im = kmkernel->identityManager();
00517   im->setAsDefault( item->identity().identityName() );
00518   refreshList();
00519 }
00520 
00521 void IdentityPage::refreshList() {
00522   for ( QListViewItemIterator it( mIdentityList ) ; it.current() ; ++it ) {
00523     IdentityListViewItem * item =
00524       dynamic_cast<IdentityListViewItem*>(it.current());
00525     if ( item )
00526       item->redisplay();
00527   }
00528   emit changed(true);
00529 }
00530 
00531 void IdentityPage::slotIdentitySelectionChanged()
00532 {
00533   IdentityListViewItem *item =
00534     dynamic_cast<IdentityListViewItem*>( mIdentityList->selectedItem() );
00535 
00536   mRemoveButton->setEnabled( item && mIdentityList->childCount() > 1 );
00537   mModifyButton->setEnabled( item );
00538   mRenameButton->setEnabled( item );
00539   mSetAsDefaultButton->setEnabled( item && !item->identity().isDefault() );
00540 }
00541 
00542 void IdentityPage::slotUpdateTransportCombo( const QStringList & sl )
00543 {
00544   if ( mIdentityDialog ) mIdentityDialog->slotUpdateTransportCombo( sl );
00545 }
00546 
00547 
00548 
00549 // *************************************************************
00550 // *                                                           *
00551 // *                       AccountsPage                         *
00552 // *                                                           *
00553 // *************************************************************
00554 QString AccountsPage::helpAnchor() const {
00555   return QString::fromLatin1("configure-accounts");
00556 }
00557 
00558 AccountsPage::AccountsPage( QWidget * parent, const char * name )
00559   : ConfigModuleWithTabs( parent, name )
00560 {
00561   //
00562   // "Receiving" tab:
00563   //
00564   mReceivingTab = new ReceivingTab();
00565   addTab( mReceivingTab, i18n( "&Receiving" ) );
00566   connect( mReceivingTab, SIGNAL(accountListChanged(const QStringList &)),
00567            this, SIGNAL(accountListChanged(const QStringList &)) );
00568 
00569   //
00570   // "Sending" tab:
00571   //
00572   mSendingTab = new SendingTab();
00573   addTab( mSendingTab, i18n( "&Sending" ) );
00574   connect( mSendingTab, SIGNAL(transportListChanged(const QStringList&)),
00575            this, SIGNAL(transportListChanged(const QStringList&)) );
00576 
00577   load();
00578 }
00579 
00580 QString AccountsPage::SendingTab::helpAnchor() const {
00581   return QString::fromLatin1("configure-accounts-sending");
00582 }
00583 
00584 AccountsPageSendingTab::AccountsPageSendingTab( QWidget * parent, const char * name )
00585   : ConfigModuleTab( parent, name )
00586 {
00587   mTransportInfoList.setAutoDelete( true );
00588   // temp. vars:
00589   QVBoxLayout *vlay;
00590   QVBoxLayout *btn_vlay;
00591   QHBoxLayout *hlay;
00592   QGridLayout *glay;
00593   QPushButton *button;
00594   QGroupBox   *group;
00595 
00596   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
00597   // label: zero stretch ### FIXME more
00598   vlay->addWidget( new QLabel( i18n("Outgoing accounts (add at least one):"), this ) );
00599 
00600   // hbox layout: stretch 10, spacing inherited from vlay
00601   hlay = new QHBoxLayout();
00602   vlay->addLayout( hlay, 10 ); // high stretch b/c of the groupbox's sizeHint
00603 
00604   // transport list: left widget in hlay; stretch 1
00605   // ### FIXME: allow inline renaming of the account:
00606   mTransportList = new ListView( this, "transportList", 5 );
00607   mTransportList->addColumn( i18n("Name") );
00608   mTransportList->addColumn( i18n("Type") );
00609   mTransportList->setAllColumnsShowFocus( true );
00610   mTransportList->setSorting( -1 );
00611   connect( mTransportList, SIGNAL(selectionChanged()),
00612            this, SLOT(slotTransportSelected()) );
00613   connect( mTransportList, SIGNAL(doubleClicked( QListViewItem *)),
00614            this, SLOT(slotModifySelectedTransport()) );
00615   hlay->addWidget( mTransportList, 1 );
00616 
00617   // a vbox layout for the buttons: zero stretch, spacing inherited from hlay
00618   btn_vlay = new QVBoxLayout( hlay );
00619 
00620   // "add..." button: stretch 0
00621   button = new QPushButton( i18n("A&dd..."), this );
00622   button->setAutoDefault( false );
00623   connect( button, SIGNAL(clicked()),
00624            this, SLOT(slotAddTransport()) );
00625   btn_vlay->addWidget( button );
00626 
00627   // "modify..." button: stretch 0
00628   mModifyTransportButton = new QPushButton( i18n("&Modify..."), this );
00629   mModifyTransportButton->setAutoDefault( false );
00630   mModifyTransportButton->setEnabled( false ); // b/c no item is selected yet
00631   connect( mModifyTransportButton, SIGNAL(clicked()),
00632            this, SLOT(slotModifySelectedTransport()) );
00633   btn_vlay->addWidget( mModifyTransportButton );
00634 
00635   // "remove" button: stretch 0
00636   mRemoveTransportButton = new QPushButton( i18n("R&emove"), this );
00637   mRemoveTransportButton->setAutoDefault( false );
00638   mRemoveTransportButton->setEnabled( false ); // b/c no item is selected yet
00639   connect( mRemoveTransportButton, SIGNAL(clicked()),
00640            this, SLOT(slotRemoveSelectedTransport()) );
00641   btn_vlay->addWidget( mRemoveTransportButton );
00642 
00643   mSetDefaultTransportButton = new QPushButton( i18n("Set Default"), this );
00644   mSetDefaultTransportButton->setAutoDefault( false );
00645   mSetDefaultTransportButton->setEnabled( false );
00646   connect ( mSetDefaultTransportButton, SIGNAL(clicked()),
00647             this, SLOT(slotSetDefaultTransport()) );
00648   btn_vlay->addWidget( mSetDefaultTransportButton );
00649   btn_vlay->addStretch( 1 ); // spacer
00650 
00651   // "Common options" groupbox:
00652   group = new QGroupBox( 0, Qt::Vertical,
00653                          i18n("Common Options"), this );
00654   vlay->addWidget(group);
00655 
00656   // a grid layout for the contents of the "common options" group box
00657   glay = new QGridLayout( group->layout(), 5, 3, KDialog::spacingHint() );
00658   glay->setColStretch( 2, 10 );
00659 
00660   // "confirm before send" check box:
00661   mConfirmSendCheck = new QCheckBox( i18n("Confirm &before send"), group );
00662   glay->addMultiCellWidget( mConfirmSendCheck, 0, 0, 0, 1 );
00663   connect( mConfirmSendCheck, SIGNAL( stateChanged( int ) ),
00664            this, SLOT( slotEmitChanged( void ) ) );
00665 
00666   // "send on check" combo:
00667   mSendOnCheckCombo = new QComboBox( false, group );
00668   mSendOnCheckCombo->insertStringList( QStringList()
00669                                       << i18n("Never Automatically")
00670                                       << i18n("On Manual Mail Checks")
00671                                       << i18n("On All Mail Checks") );
00672   glay->addWidget( mSendOnCheckCombo, 1, 1 );
00673   connect( mSendOnCheckCombo, SIGNAL( activated( int ) ),
00674            this, SLOT( slotEmitChanged( void ) ) );
00675 
00676   // "default send method" combo:
00677   mSendMethodCombo = new QComboBox( false, group );
00678   mSendMethodCombo->insertStringList( QStringList()
00679                                       << i18n("Send Now")
00680                                       << i18n("Send Later") );
00681   glay->addWidget( mSendMethodCombo, 2, 1 );
00682   connect( mSendMethodCombo, SIGNAL( activated( int ) ),
00683            this, SLOT( slotEmitChanged( void ) ) );
00684 
00685 
00686   // "message property" combo:
00687   // ### FIXME: remove completely?
00688   mMessagePropertyCombo = new QComboBox( false, group );
00689   mMessagePropertyCombo->insertStringList( QStringList()
00690                      << i18n("Allow 8-bit")
00691                      << i18n("MIME Compliant (Quoted Printable)") );
00692   glay->addWidget( mMessagePropertyCombo, 3, 1 );
00693   connect( mMessagePropertyCombo, SIGNAL( activated( int ) ),
00694            this, SLOT( slotEmitChanged( void ) ) );
00695 
00696   // "default domain" input field:
00697   mDefaultDomainEdit = new KLineEdit( group );
00698   glay->addMultiCellWidget( mDefaultDomainEdit, 4, 4, 1, 2 );
00699   connect( mDefaultDomainEdit, SIGNAL( textChanged( const QString& ) ),
00700            this, SLOT( slotEmitChanged( void ) ) );
00701 
00702   // labels:
00703   QLabel *l =  new QLabel( mSendOnCheckCombo, /*buddy*/
00704                             i18n("Send &messages in outbox folder:"), group );
00705   glay->addWidget( l, 1, 0 );
00706 
00707   QString msg = i18n( GlobalSettings::self()->sendOnCheckItem()->whatsThis().utf8() );
00708   QWhatsThis::add( l, msg );
00709   QWhatsThis::add( mSendOnCheckCombo, msg );
00710 
00711   glay->addWidget( new QLabel( mSendMethodCombo, /*buddy*/
00712                                i18n("Defa&ult send method:"), group ), 2, 0 );
00713   glay->addWidget( new QLabel( mMessagePropertyCombo, /*buddy*/
00714                                i18n("Message &property:"), group ), 3, 0 );
00715   l = new QLabel( mDefaultDomainEdit, /*buddy*/
00716                           i18n("Defaul&t domain:"), group );
00717   glay->addWidget( l, 4, 0 );
00718 
00719   // and now: add QWhatsThis:
00720   msg = i18n( "<qt><p>The default domain is used to complete email "
00721               "addresses that only consist of the user's name."
00722               "</p></qt>" );
00723   QWhatsThis::add( l, msg );
00724   QWhatsThis::add( mDefaultDomainEdit, msg );
00725 }
00726 
00727 
00728 void AccountsPage::SendingTab::slotTransportSelected()
00729 {
00730   QListViewItem *cur = mTransportList->selectedItem();
00731   mModifyTransportButton->setEnabled( cur );
00732   mRemoveTransportButton->setEnabled( cur );
00733   mSetDefaultTransportButton->setEnabled( cur );
00734 }
00735 
00736 // adds a number to @p name to make the name unique
00737 static inline QString uniqueName( const QStringList & list,
00738                                   const QString & name )
00739 {
00740   int suffix = 1;
00741   QString result = name;
00742   while ( list.find( result ) != list.end() ) {
00743     result = i18n("%1: name; %2: number appended to it to make it unique "
00744                   "among a list of names", "%1 %2")
00745       .arg( name ).arg( suffix );
00746     suffix++;
00747   }
00748   return result;
00749 }
00750 
00751 void AccountsPage::SendingTab::slotSetDefaultTransport()
00752 {
00753   QListViewItem *item = mTransportList->selectedItem();
00754   if ( !item ) return;
00755 
00756   KMTransportInfo ti;
00757 
00758   QListViewItemIterator it( mTransportList );
00759   for ( ; it.current(); ++it ) {
00760   ti.readConfig( KMTransportInfo::findTransport( it.current()->text(0) ));
00761   if ( ti.type != "sendmail" ) {
00762     it.current()->setText( 1, "smtp" );
00763   } else {
00764     it.current()->setText( 1, "sendmail" );
00765     }
00766   }
00767 
00768   if ( item->text(1) != "sendmail" ) {
00769     item->setText( 1, i18n( "smtp (Default)" ));
00770   } else {
00771     item->setText( 1, i18n( "sendmail (Default)" ));
00772   }
00773   GlobalSettings::self()->setDefaultTransport( item->text(0) );
00774 
00775 }
00776 
00777 void AccountsPage::SendingTab::slotAddTransport()
00778 {
00779   int transportType;
00780 
00781   { // limit scope of selDialog
00782     KMTransportSelDlg selDialog( this );
00783     if ( selDialog.exec() != QDialog::Accepted ) return;
00784     transportType = selDialog.selected();
00785   }
00786 
00787   KMTransportInfo *transportInfo = new KMTransportInfo();
00788   switch ( transportType ) {
00789   case 0: // smtp
00790     transportInfo->type = QString::fromLatin1("smtp");
00791     break;
00792   case 1: // sendmail
00793     transportInfo->type = QString::fromLatin1("sendmail");
00794     transportInfo->name = i18n("Sendmail");
00795     transportInfo->host = _PATH_SENDMAIL; // ### FIXME: use const, not #define
00796     break;
00797   default:
00798     assert( 0 );
00799   }
00800 
00801   KMTransportDialog dialog( i18n("Add Transport"), transportInfo, this );
00802 
00803   // create list of names:
00804   // ### move behind dialog.exec()?
00805   QStringList transportNames;
00806   QPtrListIterator<KMTransportInfo> it( mTransportInfoList );
00807   for ( it.toFirst() ; it.current() ; ++it )
00808     transportNames << (*it)->name;
00809 
00810   if( dialog.exec() != QDialog::Accepted ) {
00811     delete transportInfo;
00812     return;
00813   }
00814 
00815   // disambiguate the name by appending a number:
00816   // ### FIXME: don't allow this error to happen in the first place!
00817   transportInfo->name = uniqueName( transportNames, transportInfo->name );
00818   // append to names and transportinfo lists:
00819   transportNames << transportInfo->name;
00820   mTransportInfoList.append( transportInfo );
00821 
00822   // append to listview:
00823   // ### FIXME: insert before the selected item, append on empty selection
00824   QListViewItem *lastItem = mTransportList->firstChild();
00825   QString typeDisplayName;
00826   if ( lastItem ) {
00827     typeDisplayName = transportInfo->type;
00828   } else {
00829     typeDisplayName = i18n("%1: type of transport. Result used in "
00830                            "Configure->Accounts->Sending listview, \"type\" "
00831                            "column, first row, to indicate that this is the "
00832                            "default transport", "%1 (Default)")
00833       .arg( transportInfo->type );
00834     GlobalSettings::self()->setDefaultTransport( transportInfo->name );
00835   }
00836   (void) new QListViewItem( mTransportList, lastItem, transportInfo->name,
00837                             typeDisplayName );
00838 
00839   // notify anyone who cares:
00840   emit transportListChanged( transportNames );
00841   emit changed( true );
00842 }
00843 
00844 void AccountsPage::SendingTab::slotModifySelectedTransport()
00845 {
00846   QListViewItem *item = mTransportList->selectedItem();
00847   if ( !item ) return;
00848 
00849   const QString& originalTransport = item->text(0);
00850 
00851   QPtrListIterator<KMTransportInfo> it( mTransportInfoList );
00852   for ( it.toFirst() ; it.current() ; ++it )
00853     if ( (*it)->name == item->text(0) ) break;
00854   if ( !it.current() ) return;
00855 
00856   KMTransportDialog dialog( i18n("Modify Transport"), (*it), this );
00857 
00858   if ( dialog.exec() != QDialog::Accepted ) return;
00859 
00860   // create the list of names of transports, but leave out the current
00861   // item:
00862   QStringList transportNames;
00863   QPtrListIterator<KMTransportInfo> jt( mTransportInfoList );
00864   int entryLocation = -1;
00865   for ( jt.toFirst() ; jt.current() ; ++jt )
00866     if ( jt != it )
00867       transportNames << (*jt)->name;
00868     else
00869       entryLocation = transportNames.count();
00870   assert( entryLocation >= 0 );
00871 
00872   // make the new name unique by appending a high enough number:
00873   (*it)->name = uniqueName( transportNames, (*it)->name );
00874   // change the list item to the new name
00875   item->setText( 0, (*it)->name );
00876   // and insert the new name at the position of the old in the list of
00877   // strings; then broadcast the new list:
00878   transportNames.insert( transportNames.at( entryLocation ), (*it)->name );
00879   const QString& newTransportName = (*it)->name;
00880 
00881   QStringList changedIdents;
00882   KPIM::IdentityManager * im = kmkernel->identityManager();
00883   for ( KPIM::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) {
00884     if ( originalTransport == (*it).transport() ) {
00885       (*it).setTransport( newTransportName );
00886       changedIdents += (*it).identityName();
00887     }
00888   }
00889 
00890   if ( !changedIdents.isEmpty() ) {
00891     QString information = i18n( "This identity has been changed to use the modified transport:",
00892                           "These %n identities have been changed to use the modified transport:",
00893                           changedIdents.count() );
00894     KMessageBox::informationList( this, information, changedIdents );
00895   }
00896 
00897   emit transportListChanged( transportNames );
00898   emit changed( true );
00899 }
00900 
00901 void AccountsPage::SendingTab::slotRemoveSelectedTransport()
00902 {
00903   QListViewItem *item = mTransportList->selectedItem();
00904   if ( !item ) return;
00905 
00906   bool selectedTransportWasDefault = false;
00907   if ( item->text( 0 ) == GlobalSettings::self()->defaultTransport() ) {
00908       selectedTransportWasDefault = true;
00909   }
00910   QStringList changedIdents;
00911   KPIM::IdentityManager * im = kmkernel->identityManager();
00912   for ( KPIM::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) {
00913     if ( item->text( 0 ) == (*it).transport() ) {
00914       (*it).setTransport( QString::null );
00915       changedIdents += (*it).identityName();
00916     }
00917   }
00918 
00919   // if the deleted transport is the currently used transport reset it to default
00920   const QString& currentTransport = GlobalSettings::self()->currentTransport();
00921   if ( item->text( 0 ) == currentTransport ) {
00922     GlobalSettings::self()->setCurrentTransport( QString::null );
00923   }
00924 
00925   if ( !changedIdents.isEmpty() ) {
00926     QString information = i18n( "This identity has been changed to use the default transport:",
00927                           "These %n identities have been changed to use the default transport:",
00928                           changedIdents.count() );
00929     KMessageBox::informationList( this, information, changedIdents );
00930   }
00931 
00932   QPtrListIterator<KMTransportInfo> it( mTransportInfoList );
00933   for ( it.toFirst() ; it.current() ; ++it )
00934     if ( (*it)->name == item->text(0) ) break;
00935   if ( !it.current() ) return;
00936 
00937   KMTransportInfo ti;
00938 
00939   if( selectedTransportWasDefault )
00940   {
00941     QListViewItem *newCurrent = item->itemBelow();
00942     if ( !newCurrent ) newCurrent = item->itemAbove();
00943     //mTransportList->removeItem( item );
00944     if ( newCurrent ) {
00945       mTransportList->setCurrentItem( newCurrent );
00946       mTransportList->setSelected( newCurrent, true );
00947       GlobalSettings::self()->setDefaultTransport( newCurrent->text(0) );
00948       ti.readConfig( KMTransportInfo::findTransport( newCurrent->text(0) ));
00949       if ( ti.type != "sendmail" ) {
00950         newCurrent->setText( 1, i18n("smtp (Default)") );
00951       } else {
00952         newCurrent->setText( 1, i18n("sendmail (Default)" ));
00953       }
00954     } else {
00955       GlobalSettings::self()->setDefaultTransport( QString::null );
00956     }
00957   }
00958   delete item;
00959   mTransportInfoList.remove( it );
00960 
00961   QStringList transportNames;
00962   for ( it.toFirst() ; it.current() ; ++it )
00963     transportNames << (*it)->name;
00964   emit transportListChanged( transportNames );
00965   emit changed( true );
00966 }
00967 
00968 void AccountsPage::SendingTab::doLoadFromGlobalSettings() {
00969   mSendOnCheckCombo->setCurrentItem( GlobalSettings::self()->sendOnCheck() );
00970 }
00971 
00972 void AccountsPage::SendingTab::doLoadOther() {
00973   KConfigGroup general( KMKernel::config(), "General");
00974   KConfigGroup composer( KMKernel::config(), "Composer");
00975 
00976   int numTransports = general.readNumEntry("transports", 0);
00977 
00978   QListViewItem *top = 0;
00979   mTransportInfoList.clear();
00980   mTransportList->clear();
00981   QStringList transportNames;
00982   for ( int i = 1 ; i <= numTransports ; i++ ) {
00983     KMTransportInfo *ti = new KMTransportInfo();
00984     ti->readConfig(i);
00985     mTransportInfoList.append( ti );
00986     transportNames << ti->name;
00987     top = new QListViewItem( mTransportList, top, ti->name, ti->type );
00988   }
00989   emit transportListChanged( transportNames );
00990 
00991   const QString &defaultTransport = GlobalSettings::self()->defaultTransport();
00992 
00993   QListViewItemIterator it( mTransportList );
00994   for ( ; it.current(); ++it ) {
00995     if ( it.current()->text(0) == defaultTransport ) {
00996       if ( it.current()->text(1) != "sendmail" ) {
00997         it.current()->setText( 1, i18n( "smtp (Default)" ));
00998       } else {
00999         it.current()->setText( 1, i18n( "sendmail (Default)" ));
01000       }
01001     } else {
01002       if ( it.current()->text(1) != "sendmail" ) {
01003         it.current()->setText( 1, "smtp" );
01004       } else {
01005         it.current()->setText( 1, "sendmail" );
01006       }
01007     }
01008   }
01009 
01010   mSendMethodCombo->setCurrentItem(
01011                 kmkernel->msgSender()->sendImmediate() ? 0 : 1 );
01012   mMessagePropertyCombo->setCurrentItem(
01013                 kmkernel->msgSender()->sendQuotedPrintable() ? 1 : 0 );
01014 
01015   mConfirmSendCheck->setChecked( composer.readBoolEntry( "confirm-before-send",
01016                                                          false ) );
01017   QString str = general.readEntry( "Default domain" );
01018   if( str.isEmpty() )
01019   {
01020     //### FIXME: Use the global convenience function instead of the homebrewed
01021     //           solution once we can rely on HEAD kdelibs.
01022     //str = KGlobal::hostname(); ???????
01023     char buffer[256];
01024     if ( !gethostname( buffer, 255 ) )
01025       // buffer need not be NUL-terminated if it has full length
01026       buffer[255] = 0;
01027     else
01028       buffer[0] = 0;
01029     str = QString::fromLatin1( *buffer ? buffer : "localhost" );
01030   }
01031   mDefaultDomainEdit->setText( str );
01032 }
01033 
01034 void AccountsPage::SendingTab::save() {
01035   KConfigGroup general( KMKernel::config(), "General" );
01036   KConfigGroup composer( KMKernel::config(), "Composer" );
01037 
01038   // Save transports:
01039   general.writeEntry( "transports", mTransportInfoList.count() );
01040   QPtrListIterator<KMTransportInfo> it( mTransportInfoList );
01041   for ( int i = 1 ; it.current() ; ++it, ++i )
01042     (*it)->writeConfig(i);
01043 
01044   // Save common options:
01045   GlobalSettings::self()->setSendOnCheck( mSendOnCheckCombo->currentItem() );
01046   kmkernel->msgSender()->setSendImmediate(
01047                              mSendMethodCombo->currentItem() == 0 );
01048   kmkernel->msgSender()->setSendQuotedPrintable(
01049                              mMessagePropertyCombo->currentItem() == 1 );
01050   kmkernel->msgSender()->writeConfig( false ); // don't sync
01051   composer.writeEntry("confirm-before-send", mConfirmSendCheck->isChecked() );
01052   general.writeEntry( "Default domain", mDefaultDomainEdit->text() );
01053 }
01054 
01055 QString AccountsPage::ReceivingTab::helpAnchor() const {
01056   return QString::fromLatin1("configure-accounts-receiving");
01057 }
01058 
01059 AccountsPageReceivingTab::AccountsPageReceivingTab( QWidget * parent, const char * name )
01060   : ConfigModuleTab ( parent, name )
01061 {
01062   // temp. vars:
01063   QVBoxLayout *vlay;
01064   QVBoxLayout *btn_vlay;
01065   QHBoxLayout *hlay;
01066   QPushButton *button;
01067   QGroupBox   *group;
01068 
01069   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
01070 
01071   // label: zero stretch
01072   vlay->addWidget( new QLabel( i18n("Incoming accounts (add at least one):"), this ) );
01073 
01074   // hbox layout: stretch 10, spacing inherited from vlay
01075   hlay = new QHBoxLayout();
01076   vlay->addLayout( hlay, 10 ); // high stretch to suppress groupbox's growing
01077 
01078   // account list: left widget in hlay; stretch 1
01079   mAccountList = new ListView( this, "accountList", 5 );
01080   mAccountList->addColumn( i18n("Name") );
01081   mAccountList->addColumn( i18n("Type") );
01082   mAccountList->addColumn( i18n("Folder") );
01083   mAccountList->setAllColumnsShowFocus( true );
01084   mAccountList->setSorting( -1 );
01085   connect( mAccountList, SIGNAL(selectionChanged()),
01086            this, SLOT(slotAccountSelected()) );
01087   connect( mAccountList, SIGNAL(doubleClicked( QListViewItem *)),
01088            this, SLOT(slotModifySelectedAccount()) );
01089   hlay->addWidget( mAccountList, 1 );
01090 
01091   // a vbox layout for the buttons: zero stretch, spacing inherited from hlay
01092   btn_vlay = new QVBoxLayout( hlay );
01093 
01094   // "add..." button: stretch 0
01095   button = new QPushButton( i18n("A&dd..."), this );
01096   button->setAutoDefault( false );
01097   connect( button, SIGNAL(clicked()),
01098            this, SLOT(slotAddAccount()) );
01099   btn_vlay->addWidget( button );
01100 
01101   // "modify..." button: stretch 0
01102   mModifyAccountButton = new QPushButton( i18n("&Modify..."), this );
01103   mModifyAccountButton->setAutoDefault( false );
01104   mModifyAccountButton->setEnabled( false ); // b/c no item is selected yet
01105   connect( mModifyAccountButton, SIGNAL(clicked()),
01106            this, SLOT(slotModifySelectedAccount()) );
01107   btn_vlay->addWidget( mModifyAccountButton );
01108 
01109   // "remove..." button: stretch 0
01110   mRemoveAccountButton = new QPushButton( i18n("R&emove"), this );
01111   mRemoveAccountButton->setAutoDefault( false );
01112   mRemoveAccountButton->setEnabled( false ); // b/c no item is selected yet
01113   connect( mRemoveAccountButton, SIGNAL(clicked()),
01114            this, SLOT(slotRemoveSelectedAccount()) );
01115   btn_vlay->addWidget( mRemoveAccountButton );
01116   btn_vlay->addStretch( 1 ); // spacer
01117 
01118   mCheckmailStartupCheck = new QCheckBox( i18n("Chec&k mail on startup"), this );
01119   vlay->addWidget( mCheckmailStartupCheck );
01120   connect( mCheckmailStartupCheck, SIGNAL( stateChanged( int ) ),
01121            this, SLOT( slotEmitChanged( void ) ) );
01122 
01123   // "New Mail Notification" group box: stretch 0
01124   group = new QVGroupBox( i18n("New Mail Notification"), this );
01125   vlay->addWidget( group );
01126   group->layout()->setSpacing( KDialog::spacingHint() );
01127 
01128   // "beep on new mail" check box:
01129   mBeepNewMailCheck = new QCheckBox(i18n("&Beep"), group );
01130   mBeepNewMailCheck->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding,
01131                                                  QSizePolicy::Fixed ) );
01132   connect( mBeepNewMailCheck, SIGNAL( stateChanged( int ) ),
01133            this, SLOT( slotEmitChanged( void ) ) );
01134 
01135   // "Detailed new mail notification" check box
01136   mVerboseNotificationCheck =
01137     new QCheckBox( i18n( "Deta&iled new mail notification" ), group );
01138   mVerboseNotificationCheck->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding,
01139                                                          QSizePolicy::Fixed ) );
01140   QToolTip::add( mVerboseNotificationCheck,
01141                  i18n( "Show for each folder the number of newly arrived "
01142                        "messages" ) );
01143   QWhatsThis::add( mVerboseNotificationCheck,
01144     GlobalSettings::self()->verboseNewMailNotificationItem()->whatsThis() );
01145   connect( mVerboseNotificationCheck, SIGNAL( stateChanged( int ) ),
01146            this, SLOT( slotEmitChanged() ) );
01147 
01148   // "Other Actions" button:
01149   mOtherNewMailActionsButton = new QPushButton( i18n("Other Actio&ns"), group );
01150   mOtherNewMailActionsButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed,
01151                                                           QSizePolicy::Fixed ) );
01152   connect( mOtherNewMailActionsButton, SIGNAL(clicked()),
01153            this, SLOT(slotEditNotifications()) );
01154 }
01155 
01156 AccountsPageReceivingTab::~AccountsPageReceivingTab()
01157 {
01158   // When hitting Cancel or closing the dialog with the window-manager-button,
01159   // we have a number of things to clean up:
01160 
01161   // The newly created accounts
01162   QValueList< QGuardedPtr<KMAccount> >::Iterator it;
01163   for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) {
01164     delete (*it);
01165   }
01166   mNewAccounts.clear();
01167 
01168   // The modified accounts
01169   QValueList<ModifiedAccountsType*>::Iterator j;
01170   for ( j = mModifiedAccounts.begin() ; j != mModifiedAccounts.end() ; ++j ) {
01171     delete (*j)->newAccount;
01172     delete (*j);
01173   }
01174   mModifiedAccounts.clear();
01175 
01176 
01177 }
01178 
01179 void AccountsPage::ReceivingTab::slotAccountSelected()
01180 {
01181   QListViewItem * item = mAccountList->selectedItem();
01182   mModifyAccountButton->setEnabled( item );
01183   mRemoveAccountButton->setEnabled( item );
01184 }
01185 
01186 QStringList AccountsPage::ReceivingTab::occupiedNames()
01187 {
01188   QStringList accountNames = kmkernel->acctMgr()->getAccounts();
01189 
01190   QValueList<ModifiedAccountsType*>::Iterator k;
01191   for (k = mModifiedAccounts.begin(); k != mModifiedAccounts.end(); ++k )
01192     if ((*k)->oldAccount)
01193       accountNames.remove( (*k)->oldAccount->name() );
01194 
01195   QValueList< QGuardedPtr<KMAccount> >::Iterator l;
01196   for (l = mAccountsToDelete.begin(); l != mAccountsToDelete.end(); ++l )
01197     if (*l)
01198       accountNames.remove( (*l)->name() );
01199 
01200   QValueList< QGuardedPtr<KMAccount> >::Iterator it;
01201   for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it )
01202     if (*it)
01203       accountNames += (*it)->name();
01204 
01205   QValueList<ModifiedAccountsType*>::Iterator j;
01206   for (j = mModifiedAccounts.begin(); j != mModifiedAccounts.end(); ++j )
01207     accountNames += (*j)->newAccount->name();
01208 
01209   return accountNames;
01210 }
01211 
01212 void AccountsPage::ReceivingTab::slotAddAccount() {
01213   KMAcctSelDlg accountSelectorDialog( this );
01214   if( accountSelectorDialog.exec() != QDialog::Accepted ) return;
01215 
01216   const char *accountType = 0;
01217   switch ( accountSelectorDialog.selected() ) {
01218     case 0: accountType = "local";      break;
01219     case 1: accountType = "pop";        break;
01220     case 2: accountType = "imap";       break;
01221     case 3: accountType = "cachedimap"; break;
01222     case 4: accountType = "maildir";    break;
01223 
01224     default:
01225       // ### FIXME: How should this happen???
01226       // replace with assert.
01227       KMessageBox::sorry( this, i18n("Unknown account type selected") );
01228       return;
01229   }
01230 
01231   KMAccount *account
01232     = kmkernel->acctMgr()->create( QString::fromLatin1( accountType ) );
01233   if ( !account ) {
01234     // ### FIXME: Give the user more information. Is this error
01235     // recoverable?
01236     KMessageBox::sorry( this, i18n("Unable to create account") );
01237     return;
01238   }
01239 
01240   account->init(); // fill the account fields with good default values
01241 
01242   AccountDialog dialog( i18n("Add Account"), account, this );
01243 
01244   QStringList accountNames = occupiedNames();
01245 
01246   if( dialog.exec() != QDialog::Accepted ) {
01247     delete account;
01248     return;
01249   }
01250 
01251   account->deinstallTimer();
01252   account->setName( uniqueName( accountNames, account->name() ) );
01253 
01254   QListViewItem *after = mAccountList->firstChild();
01255   while ( after && after->nextSibling() )
01256     after = after->nextSibling();
01257 
01258   QListViewItem *listItem =
01259     new QListViewItem( mAccountList, after, account->name(), account->type() );
01260   if( account->folder() )
01261     listItem->setText( 2, account->folder()->label() );
01262 
01263   mNewAccounts.append( account );
01264   emit changed( true );
01265 }
01266 
01267 
01268 
01269 void AccountsPage::ReceivingTab::slotModifySelectedAccount()
01270 {
01271   QListViewItem *listItem = mAccountList->selectedItem();
01272   if( !listItem ) return;
01273 
01274   KMAccount *account = 0;
01275   QValueList<ModifiedAccountsType*>::Iterator j;
01276   for (j = mModifiedAccounts.begin(); j != mModifiedAccounts.end(); ++j )
01277     if ( (*j)->newAccount->name() == listItem->text(0) ) {
01278       account = (*j)->newAccount;
01279       break;
01280     }
01281 
01282   if ( !account ) {
01283     QValueList< QGuardedPtr<KMAccount> >::Iterator it;
01284     for ( it = mNewAccounts.begin() ; it != mNewAccounts.end() ; ++it )
01285       if ( (*it)->name() == listItem->text(0) ) {
01286         account = *it;
01287         break;
01288       }
01289 
01290     if ( !account ) {
01291       account = kmkernel->acctMgr()->findByName( listItem->text(0) );
01292       if( !account ) {
01293         // ### FIXME: How should this happen? See above.
01294         KMessageBox::sorry( this, i18n("Unable to locate account") );
01295         return;
01296       }
01297       if ( account->type() == "imap" || account->type() == "cachedimap" )
01298       {
01299         ImapAccountBase* ai = static_cast<ImapAccountBase*>( account );
01300         if ( ai->namespaces().isEmpty() || ai->namespaceToDelimiter().isEmpty() )
01301         {
01302           // connect to server - the namespaces are fetched automatically
01303           kdDebug(5006) << "slotModifySelectedAccount - connect" << endl;
01304           ai->makeConnection();
01305         }
01306       }
01307 
01308       ModifiedAccountsType *mod = new ModifiedAccountsType;
01309       mod->oldAccount = account;
01310       mod->newAccount = kmkernel->acctMgr()->create( account->type(),
01311                                                    account->name() );
01312       mod->newAccount->pseudoAssign( account );
01313       mModifiedAccounts.append( mod );
01314       account = mod->newAccount;
01315     }
01316   }
01317 
01318   QStringList accountNames = occupiedNames();
01319   accountNames.remove( account->name() );
01320 
01321   AccountDialog dialog( i18n("Modify Account"), account, this );
01322 
01323   if( dialog.exec() != QDialog::Accepted ) return;
01324 
01325   account->setName( uniqueName( accountNames, account->name() ) );
01326 
01327   listItem->setText( 0, account->name() );
01328   listItem->setText( 1, account->type() );
01329   if( account->folder() )
01330     listItem->setText( 2, account->folder()->label() );
01331 
01332   emit changed( true );
01333 }
01334 
01335 
01336 
01337 void AccountsPage::ReceivingTab::slotRemoveSelectedAccount() {
01338   QListViewItem *listItem = mAccountList->selectedItem();
01339   if( !listItem ) return;
01340 
01341   KMAccount *acct = 0;
01342   QValueList<ModifiedAccountsType*>::Iterator j;
01343   for ( j = mModifiedAccounts.begin() ; j != mModifiedAccounts.end() ; ++j )
01344     if ( (*j)->newAccount->name() == listItem->text(0) ) {
01345       acct = (*j)->oldAccount;
01346       mAccountsToDelete.append( acct );
01347       mModifiedAccounts.remove( j );
01348       break;
01349     }
01350   if ( !acct ) {
01351     QValueList< QGuardedPtr<KMAccount> >::Iterator it;
01352     for ( it = mNewAccounts.begin() ; it != mNewAccounts.end() ; ++it )
01353       if ( (*it)->name() == listItem->text(0) ) {
01354         acct = *it;
01355         mNewAccounts.remove( it );
01356         break;
01357       }
01358   }
01359   if ( !acct ) {
01360     acct = kmkernel->acctMgr()->findByName( listItem->text(0) );
01361     if ( acct )
01362       mAccountsToDelete.append( acct );
01363   }
01364   if ( !acct ) {
01365     // ### FIXME: see above
01366     KMessageBox::sorry( this, i18n("<qt>Unable to locate account <b>%1</b>.</qt>")
01367                         .arg(listItem->text(0)) );
01368     return;
01369   }
01370 
01371   QListViewItem * item = listItem->itemBelow();
01372   if ( !item ) item = listItem->itemAbove();
01373   delete listItem;
01374 
01375   if ( item )
01376     mAccountList->setSelected( item, true );
01377 
01378   emit changed( true );
01379 }
01380 
01381 void AccountsPage::ReceivingTab::slotEditNotifications()
01382 {
01383   if(kmkernel->xmlGuiInstance())
01384     KNotifyDialog::configure(this, 0, kmkernel->xmlGuiInstance()->aboutData());
01385   else
01386     KNotifyDialog::configure(this);
01387 }
01388 
01389 void AccountsPage::ReceivingTab::doLoadFromGlobalSettings() {
01390   mVerboseNotificationCheck->setChecked( GlobalSettings::self()->verboseNewMailNotification() );
01391 }
01392 
01393 void AccountsPage::ReceivingTab::doLoadOther() {
01394   KConfigGroup general( KMKernel::config(), "General" );
01395 
01396   mAccountList->clear();
01397   QListViewItem *top = 0;
01398 
01399   for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0;
01400        a = kmkernel->acctMgr()->next() ) {
01401     QListViewItem *listItem =
01402       new QListViewItem( mAccountList, top, a->name(), a->type() );
01403     if( a->folder() )
01404       listItem->setText( 2, a->folder()->label() );
01405     top = listItem;
01406   }
01407   QListViewItem *listItem = mAccountList->firstChild();
01408   if ( listItem ) {
01409     mAccountList->setCurrentItem( listItem );
01410     mAccountList->setSelected( listItem, true );
01411   }
01412 
01413   mBeepNewMailCheck->setChecked( general.readBoolEntry("beep-on-mail", false ) );
01414   mCheckmailStartupCheck->setChecked( general.readBoolEntry("checkmail-startup", false) );
01415   QTimer::singleShot( 0, this, SLOT( slotTweakAccountList() ) );
01416 }
01417 
01418 void AccountsPage::ReceivingTab::slotTweakAccountList()
01419 {
01420   // Force the contentsWidth of mAccountList to be recalculated so that items can be
01421   // selected in the normal way. It would be best if this were not necessary.
01422   mAccountList->resizeContents( mAccountList->visibleWidth(), mAccountList->contentsHeight() );
01423 }
01424 
01425 void AccountsPage::ReceivingTab::save() {
01426   // Add accounts marked as new
01427   QValueList< QGuardedPtr<KMAccount> >::Iterator it;
01428   for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) {
01429     kmkernel->acctMgr()->add( *it ); // calls installTimer too
01430   }
01431 
01432   // Update accounts that have been modified
01433   QValueList<ModifiedAccountsType*>::Iterator j;
01434   for ( j = mModifiedAccounts.begin() ; j != mModifiedAccounts.end() ; ++j ) {
01435     (*j)->oldAccount->pseudoAssign( (*j)->newAccount );
01436     delete (*j)->newAccount;
01437     delete (*j);
01438   }
01439   mModifiedAccounts.clear();
01440 
01441   // Delete accounts marked for deletion
01442   for ( it = mAccountsToDelete.begin() ;
01443         it != mAccountsToDelete.end() ; ++it ) {
01444     kmkernel->acctMgr()->writeConfig( true );
01445     if ( (*it) && !kmkernel->acctMgr()->remove(*it) )
01446       KMessageBox::sorry( this, i18n("<qt>Unable to locate account <b>%1</b>.</qt>")
01447                           .arg( (*it)->name() ) );
01448   }
01449   mAccountsToDelete.clear();
01450 
01451   // Incoming mail
01452   kmkernel->acctMgr()->writeConfig( false );
01453   kmkernel->cleanupImapFolders();
01454 
01455   // Save Mail notification settings
01456   KConfigGroup general( KMKernel::config(), "General" );
01457   general.writeEntry( "beep-on-mail", mBeepNewMailCheck->isChecked() );
01458   GlobalSettings::self()->setVerboseNewMailNotification( mVerboseNotificationCheck->isChecked() );
01459 
01460   general.writeEntry( "checkmail-startup", mCheckmailStartupCheck->isChecked() );
01461 
01462   // Sync new IMAP accounts ASAP:
01463   for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) {
01464     KMAccount *macc = (*it);
01465     ImapAccountBase *acc = dynamic_cast<ImapAccountBase*> (macc);
01466     if ( acc ) {
01467       AccountUpdater *au = new AccountUpdater( acc );
01468       au->update();
01469     }
01470   }
01471   mNewAccounts.clear();
01472 
01473 }
01474 
01475 // *************************************************************
01476 // *                                                           *
01477 // *                     AppearancePage                        *
01478 // *                                                           *
01479 // *************************************************************
01480 QString AppearancePage::helpAnchor() const {
01481   return QString::fromLatin1("configure-appearance");
01482 }
01483 
01484 AppearancePage::AppearancePage( QWidget * parent, const char * name )
01485   : ConfigModuleWithTabs( parent, name )
01486 {
01487   //
01488   // "Fonts" tab:
01489   //
01490   mFontsTab = new FontsTab();
01491   addTab( mFontsTab, i18n("&Fonts") );
01492 
01493   //
01494   // "Colors" tab:
01495   //
01496   mColorsTab = new ColorsTab();
01497   addTab( mColorsTab, i18n("Color&s") );
01498 
01499   //
01500   // "Layout" tab:
01501   //
01502   mLayoutTab = new LayoutTab();
01503   addTab( mLayoutTab, i18n("La&yout") );
01504 
01505   //
01506   // "Headers" tab:
01507   //
01508   mHeadersTab = new HeadersTab();
01509   addTab( mHeadersTab, i18n("M&essage List") );
01510 
01511   //
01512   // "Reader window" tab:
01513   //
01514   mReaderTab = new ReaderTab();
01515   addTab( mReaderTab, i18n("Message W&indow") );
01516 
01517   //
01518   // "System Tray" tab:
01519   //
01520   mSystemTrayTab = new SystemTrayTab();
01521   addTab( mSystemTrayTab, i18n("System &Tray") );
01522 
01523   load();
01524 }
01525 
01526 
01527 QString AppearancePage::FontsTab::helpAnchor() const {
01528   return QString::fromLatin1("configure-appearance-fonts");
01529 }
01530 
01531 static const struct {
01532   const char * configName;
01533   const char * displayName;
01534   bool   enableFamilyAndSize;
01535   bool   onlyFixed;
01536 } fontNames[] = {
01537   { "body-font", I18N_NOOP("Message Body"), true, false },
01538   { "list-font", I18N_NOOP("Message List"), true, false },
01539   { "list-new-font", I18N_NOOP("Message List - New Messages"), true, false },
01540   { "list-unread-font", I18N_NOOP("Message List - Unread Messages"), true, false },
01541   { "list-important-font", I18N_NOOP("Message List - Important Messages"), true, false },
01542   { "list-todo-font", I18N_NOOP("Message List - Todo Messages"), true, false },
01543   { "list-date-font", I18N_NOOP("Message List - Date Field"), true, false },
01544   { "folder-font", I18N_NOOP("Folder List"), true, false },
01545   { "quote1-font", I18N_NOOP("Quoted Text - First Level"), false, false },
01546   { "quote2-font", I18N_NOOP("Quoted Text - Second Level"), false, false },
01547   { "quote3-font", I18N_NOOP("Quoted Text - Third Level"), false, false },
01548   { "fixed-font", I18N_NOOP("Fixed Width Font"), true, true },
01549   { "composer-font", I18N_NOOP("Composer"), true, false },
01550   { "print-font",  I18N_NOOP("Printing Output"), true, false },
01551 };
01552 static const int numFontNames = sizeof fontNames / sizeof *fontNames;
01553 
01554 AppearancePageFontsTab::AppearancePageFontsTab( QWidget * parent, const char * name )
01555   : ConfigModuleTab( parent, name ), mActiveFontIndex( -1 )
01556 {
01557   assert( numFontNames == sizeof mFont / sizeof *mFont );
01558   // tmp. vars:
01559   QVBoxLayout *vlay;
01560   QHBoxLayout *hlay;
01561   QLabel      *label;
01562 
01563   // "Use custom fonts" checkbox, followed by <hr>
01564   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
01565   mCustomFontCheck = new QCheckBox( i18n("&Use custom fonts"), this );
01566   vlay->addWidget( mCustomFontCheck );
01567   vlay->addWidget( new KSeparator( KSeparator::HLine, this ) );
01568   connect ( mCustomFontCheck, SIGNAL( stateChanged( int ) ),
01569             this, SLOT( slotEmitChanged( void ) ) );
01570 
01571   // "font location" combo box and label:
01572   hlay = new QHBoxLayout( vlay ); // inherites spacing
01573   mFontLocationCombo = new QComboBox( false, this );
01574   mFontLocationCombo->setEnabled( false ); // !mCustomFontCheck->isChecked()
01575 
01576   QStringList fontDescriptions;
01577   for ( int i = 0 ; i < numFontNames ; i++ )
01578     fontDescriptions << i18n( fontNames[i].displayName );
01579   mFontLocationCombo->insertStringList( fontDescriptions );
01580 
01581   label = new QLabel( mFontLocationCombo, i18n("Apply &to:"), this );
01582   label->setEnabled( false ); // since !mCustomFontCheck->isChecked()
01583   hlay->addWidget( label );
01584 
01585   hlay->addWidget( mFontLocationCombo );
01586   hlay->addStretch( 10 );
01587   vlay->addSpacing( KDialog::spacingHint() );
01588   mFontChooser = new KFontChooser( this, "font", false, QStringList(),
01589                                    false, 4 );
01590   mFontChooser->setEnabled( false ); // since !mCustomFontCheck->isChecked()
01591   vlay->addWidget( mFontChooser );
01592   connect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ),
01593             this, SLOT( slotEmitChanged( void ) ) );
01594 
01595 
01596   // {en,dis}able widgets depending on the state of mCustomFontCheck:
01597   connect( mCustomFontCheck, SIGNAL(toggled(bool)),
01598            label, SLOT(setEnabled(bool)) );
01599   connect( mCustomFontCheck, SIGNAL(toggled(bool)),
01600            mFontLocationCombo, SLOT(setEnabled(bool)) );
01601   connect( mCustomFontCheck, SIGNAL(toggled(bool)),
01602            mFontChooser, SLOT(setEnabled(bool)) );
01603   // load the right font settings into mFontChooser:
01604   connect( mFontLocationCombo, SIGNAL(activated(int) ),
01605            this, SLOT(slotFontSelectorChanged(int)) );
01606 }
01607 
01608 
01609 void AppearancePage::FontsTab::slotFontSelectorChanged( int index )
01610 {
01611   kdDebug(5006) << "slotFontSelectorChanged() called" << endl;
01612   if( index < 0 || index >= mFontLocationCombo->count() )
01613     return; // Should never happen, but it is better to check.
01614 
01615   // Save current fontselector setting before we install the new:
01616   if( mActiveFontIndex == 0 ) {
01617     mFont[0] = mFontChooser->font();
01618     // hardcode the family and size of "message body" dependant fonts:
01619     for ( int i = 0 ; i < numFontNames ; i++ )
01620       if ( !fontNames[i].enableFamilyAndSize ) {
01621         // ### shall we copy the font and set the save and re-set
01622         // {regular,italic,bold,bold italic} property or should we
01623         // copy only family and pointSize?
01624         mFont[i].setFamily( mFont[0].family() );
01625         mFont[i].setPointSize/*Float?*/( mFont[0].pointSize/*Float?*/() );
01626       }
01627   } else if ( mActiveFontIndex > 0 )
01628     mFont[ mActiveFontIndex ] = mFontChooser->font();
01629   mActiveFontIndex = index;
01630 
01631   // Disonnect so the "Apply" button is not activated by the change
01632   disconnect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ),
01633             this, SLOT( slotEmitChanged( void ) ) );
01634 
01635   // Display the new setting:
01636   mFontChooser->setFont( mFont[index], fontNames[index].onlyFixed );
01637 
01638   connect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ),
01639             this, SLOT( slotEmitChanged( void ) ) );
01640 
01641   // Disable Family and Size list if we have selected a quote font:
01642   mFontChooser->enableColumn( KFontChooser::FamilyList|KFontChooser::SizeList,
01643                               fontNames[ index ].enableFamilyAndSize );
01644 }
01645 
01646 void AppearancePage::FontsTab::doLoadOther() {
01647   KConfigGroup fonts( KMKernel::config(), "Fonts" );
01648 
01649   mFont[0] = KGlobalSettings::generalFont();
01650   QFont fixedFont = KGlobalSettings::fixedFont();
01651   for ( int i = 0 ; i < numFontNames ; i++ )
01652     mFont[i] = fonts.readFontEntry( fontNames[i].configName,
01653       (fontNames[i].onlyFixed) ? &fixedFont : &mFont[0] );
01654 
01655   mCustomFontCheck->setChecked( !fonts.readBoolEntry( "defaultFonts", true ) );
01656   mFontLocationCombo->setCurrentItem( 0 );
01657   slotFontSelectorChanged( 0 );
01658 }
01659 
01660 void AppearancePage::FontsTab::installProfile( KConfig * profile ) {
01661   KConfigGroup fonts( profile, "Fonts" );
01662 
01663   // read fonts that are defined in the profile:
01664   bool needChange = false;
01665   for ( int i = 0 ; i < numFontNames ; i++ )
01666     if ( fonts.hasKey( fontNames[i].configName ) ) {
01667       needChange = true;
01668       mFont[i] = fonts.readFontEntry( fontNames[i].configName );
01669       kdDebug(5006) << "got font \"" << fontNames[i].configName
01670                 << "\" thusly: \"" << mFont[i].toString() << "\"" << endl;
01671     }
01672   if ( needChange && mFontLocationCombo->currentItem() > 0 )
01673     mFontChooser->setFont( mFont[ mFontLocationCombo->currentItem() ],
01674       fontNames[ mFontLocationCombo->currentItem() ].onlyFixed );
01675 
01676   if ( fonts.hasKey( "defaultFonts" ) )
01677     mCustomFontCheck->setChecked( !fonts.readBoolEntry( "defaultFonts" ) );
01678 }
01679 
01680 void AppearancePage::FontsTab::save() {
01681   KConfigGroup fonts( KMKernel::config(), "Fonts" );
01682 
01683   // read the current font (might have been modified)
01684   if ( mActiveFontIndex >= 0 )
01685     mFont[ mActiveFontIndex ] = mFontChooser->font();
01686 
01687   bool customFonts = mCustomFontCheck->isChecked();
01688   fonts.writeEntry( "defaultFonts", !customFonts );
01689   for ( int i = 0 ; i < numFontNames ; i++ )
01690     if ( customFonts || fonts.hasKey( fontNames[i].configName ) )
01691       // Don't write font info when we use default fonts, but write
01692       // if it's already there:
01693       fonts.writeEntry( fontNames[i].configName, mFont[i] );
01694 }
01695 
01696 QString AppearancePage::ColorsTab::helpAnchor() const {
01697   return QString::fromLatin1("configure-appearance-colors");
01698 }
01699 
01700 
01701 static const struct {
01702   const char * configName;
01703   const char * displayName;
01704 } colorNames[] = { // adjust setup() if you change this:
01705   { "BackgroundColor", I18N_NOOP("Composer Background") },
01706   { "AltBackgroundColor", I18N_NOOP("Alternative Background Color") },
01707   { "ForegroundColor", I18N_NOOP("Normal Text") },
01708   { "QuotedText1", I18N_NOOP("Quoted Text - First Level") },
01709   { "QuotedText2", I18N_NOOP("Quoted Text - Second Level") },
01710   { "QuotedText3", I18N_NOOP("Quoted Text - Third Level") },
01711   { "LinkColor", I18N_NOOP("Link") },
01712   { "FollowedColor", I18N_NOOP("Followed Link") },
01713   { "MisspelledColor", I18N_NOOP("Misspelled Words") },
01714   { "NewMessage", I18N_NOOP("New Message") },
01715   { "UnreadMessage", I18N_NOOP("Unread Message") },
01716   { "FlagMessage", I18N_NOOP("Important Message") },
01717   { "TodoMessage", I18N_NOOP("Todo Message") },
01718   { "PGPMessageEncr", I18N_NOOP("OpenPGP Message - Encrypted") },
01719   { "PGPMessageOkKeyOk", I18N_NOOP("OpenPGP Message - Valid Signature with Trusted Key") },
01720   { "PGPMessageOkKeyBad", I18N_NOOP("OpenPGP Message - Valid Signature with Untrusted Key") },
01721   { "PGPMessageWarn", I18N_NOOP("OpenPGP Message - Unchecked Signature") },
01722   { "PGPMessageErr", I18N_NOOP("OpenPGP Message - Bad Signature") },
01723   { "HTMLWarningColor", I18N_NOOP("Border Around Warning Prepending HTML Messages") },
01724   { "CloseToQuotaColor", I18N_NOOP("Folder Name and Size When Close to Quota") },
01725   { "ColorbarBackgroundPlain", I18N_NOOP("HTML Status Bar Background - No HTML Message") },
01726   { "ColorbarForegroundPlain", I18N_NOOP("HTML Status Bar Foreground - No HTML Message") },
01727   { "ColorbarBackgroundHTML",  I18N_NOOP("HTML Status Bar Background - HTML Message") },
01728   { "ColorbarForegroundHTML",  I18N_NOOP("HTML Status Bar Foreground - HTML Message") },
01729 };
01730 static const int numColorNames = sizeof colorNames / sizeof *colorNames;
01731 
01732 AppearancePageColorsTab::AppearancePageColorsTab( QWidget * parent, const char * name )
01733   : ConfigModuleTab( parent, name )
01734 {
01735   // tmp. vars:
01736   QVBoxLayout *vlay;
01737 
01738   // "use custom colors" check box
01739   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
01740   mCustomColorCheck = new QCheckBox( i18n("&Use custom colors"), this );
01741   vlay->addWidget( mCustomColorCheck );
01742   connect( mCustomColorCheck, SIGNAL( stateChanged( int ) ),
01743            this, SLOT( slotEmitChanged( void ) ) );
01744 
01745   // color list box:
01746   mColorList = new ColorListBox( this );
01747   mColorList->setEnabled( false ); // since !mCustomColorCheck->isChecked()
01748   QStringList modeList;
01749   for ( int i = 0 ; i < numColorNames ; i++ )
01750     mColorList->insertItem( new ColorListItem( i18n( colorNames[i].displayName ) ) );
01751   vlay->addWidget( mColorList, 1 );
01752 
01753   // "recycle colors" check box:
01754   mRecycleColorCheck =
01755     new QCheckBox( i18n("Recycle colors on deep &quoting"), this );
01756   mRecycleColorCheck->setEnabled( false );
01757   vlay->addWidget( mRecycleColorCheck );
01758   connect( mRecycleColorCheck, SIGNAL( stateChanged( int ) ),
01759            this, SLOT( slotEmitChanged( void ) ) );
01760 
01761   // close to quota threshold
01762   QHBoxLayout *hbox = new QHBoxLayout(vlay);
01763   QLabel *l = new QLabel( i18n("Close to quota threshold"), this );
01764   hbox->addWidget( l );
01765   l->setEnabled( false );
01766   mCloseToQuotaThreshold = new QSpinBox( 0, 100, 1, this );
01767   connect( mCloseToQuotaThreshold, SIGNAL( valueChanged( int ) ),
01768            this, SLOT( slotEmitChanged( void ) ) );
01769   mCloseToQuotaThreshold->setEnabled( false );
01770   mCloseToQuotaThreshold->setSuffix( i18n("%"));
01771   hbox->addWidget( mCloseToQuotaThreshold );
01772   hbox->addWidget( new QWidget(this), 2 );
01773 
01774   // {en,dir}able widgets depending on the state of mCustomColorCheck:
01775   connect( mCustomColorCheck, SIGNAL(toggled(bool)),
01776            mColorList, SLOT(setEnabled(bool)) );
01777   connect( mCustomColorCheck, SIGNAL(toggled(bool)),
01778            mRecycleColorCheck, SLOT(setEnabled(bool)) );
01779   connect( mCustomColorCheck, SIGNAL(toggled(bool)),
01780            l, SLOT(setEnabled(bool)) );
01781   connect( mCustomColorCheck, SIGNAL(toggled(bool)),
01782        mCloseToQuotaThreshold, SLOT(setEnabled(bool)) );
01783 
01784   connect( mCustomColorCheck, SIGNAL( stateChanged( int ) ),
01785            this, SLOT( slotEmitChanged( void ) ) );
01786 }
01787 
01788 void AppearancePage::ColorsTab::doLoadOther() {
01789   KConfigGroup reader( KMKernel::config(), "Reader" );
01790 
01791   mCustomColorCheck->setChecked( !reader.readBoolEntry( "defaultColors", true ) );
01792   mRecycleColorCheck->setChecked( reader.readBoolEntry( "RecycleQuoteColors", false ) );
01793   mCloseToQuotaThreshold->setValue( GlobalSettings::closeToQuotaThreshold() );
01794 
01795   static const QColor defaultColor[ numColorNames ] = {
01796     kapp->palette().active().base(), // bg
01797     KGlobalSettings::alternateBackgroundColor(), // alt bg
01798     kapp->palette().active().text(), // fg
01799     QColor( 0x00, 0x80, 0x00 ), // quoted l1
01800     QColor( 0x00, 0x70, 0x00 ), // quoted l2
01801     QColor( 0x00, 0x60, 0x00 ), // quoted l3
01802     KGlobalSettings::linkColor(), // link
01803     KGlobalSettings::visitedLinkColor(), // visited link
01804     Qt::red, // misspelled words
01805     Qt::red, // new msg
01806     Qt::blue, // unread mgs
01807     QColor( 0x00, 0x7F, 0x00 ), // important msg
01808     Qt::blue, // todo mgs
01809     QColor( 0x00, 0x80, 0xFF ), // light blue // pgp encrypted
01810     QColor( 0x40, 0xFF, 0x40 ), // light green // pgp ok, trusted key
01811     QColor( 0xFF, 0xFF, 0x40 ), // light yellow // pgp ok, untrusted key
01812     QColor( 0xFF, 0xFF, 0x40 ), // light yellow // pgp unchk
01813     Qt::red, // pgp bad
01814     QColor( 0xFF, 0x40, 0x40 ), // warning text color: light red
01815     Qt::red, // close to quota
01816     Qt::lightGray, // colorbar plain bg
01817     Qt::black,     // colorbar plain fg
01818     Qt::black,     // colorbar html  bg
01819     Qt::white,     // colorbar html  fg
01820   };
01821 
01822   for ( int i = 0 ; i < numColorNames ; i++ ) {
01823     mColorList->setColor( i,
01824       reader.readColorEntry( colorNames[i].configName, &defaultColor[i] ) );
01825   }
01826   connect( mColorList, SIGNAL( changed( ) ),
01827            this, SLOT( slotEmitChanged( void ) ) );
01828 }
01829 
01830 void AppearancePage::ColorsTab::installProfile( KConfig * profile ) {
01831   KConfigGroup reader( profile, "Reader" );
01832 
01833   if ( reader.hasKey( "defaultColors" ) )
01834     mCustomColorCheck->setChecked( !reader.readBoolEntry( "defaultColors" ) );
01835   if ( reader.hasKey( "RecycleQuoteColors" ) )
01836     mRecycleColorCheck->setChecked( reader.readBoolEntry( "RecycleQuoteColors" ) );
01837 
01838   for ( int i = 0 ; i < numColorNames ; i++ )
01839     if ( reader.hasKey( colorNames[i].configName ) )
01840       mColorList->setColor( i, reader.readColorEntry( colorNames[i].configName ) );
01841 }
01842 
01843 void AppearancePage::ColorsTab::save() {
01844   KConfigGroup reader( KMKernel::config(), "Reader" );
01845 
01846   bool customColors = mCustomColorCheck->isChecked();
01847   reader.writeEntry( "defaultColors", !customColors );
01848 
01849   for ( int i = 0 ; i < numColorNames ; i++ )
01850     // Don't write color info when we use default colors, but write
01851     // if it's already there:
01852     if ( customColors || reader.hasKey( colorNames[i].configName ) )
01853       reader.writeEntry( colorNames[i].configName, mColorList->color(i) );
01854 
01855   reader.writeEntry( "RecycleQuoteColors", mRecycleColorCheck->isChecked() );
01856   GlobalSettings::setCloseToQuotaThreshold( mCloseToQuotaThreshold->value() );
01857 }
01858 
01859 QString AppearancePage::LayoutTab::helpAnchor() const {
01860   return QString::fromLatin1("configure-appearance-layout");
01861 }
01862 
01863 static const EnumConfigEntryItem folderListModes[] = {
01864   { "long", I18N_NOOP("Lon&g folder list") },
01865   { "short", I18N_NOOP("Shor&t folder list" ) }
01866 };
01867 static const EnumConfigEntry folderListMode = {
01868   "Geometry", "FolderList", I18N_NOOP("Folder List"),
01869   folderListModes, DIM(folderListModes), 0
01870 };
01871 
01872 
01873 static const EnumConfigEntryItem mimeTreeLocations[] = {
01874   { "top", I18N_NOOP("Abo&ve the message pane") },
01875   { "bottom", I18N_NOOP("&Below the message pane") }
01876 };
01877 static const EnumConfigEntry mimeTreeLocation = {
01878   "Reader", "MimeTreeLocation", I18N_NOOP("Message Structure Viewer Placement"),
01879   mimeTreeLocations, DIM(mimeTreeLocations), 1
01880 };
01881 
01882 static const EnumConfigEntryItem mimeTreeModes[] = {
01883   { "never", I18N_NOOP("Show &never") },
01884   { "smart", I18N_NOOP("Show only for non-plaintext &messages") },
01885   { "always", I18N_NOOP("Show alway&s") }
01886 };
01887 static const EnumConfigEntry mimeTreeMode = {
01888   "Reader", "MimeTreeMode", I18N_NOOP("Message Structure Viewer"),
01889   mimeTreeModes, DIM(mimeTreeModes), 1
01890 };
01891 
01892 
01893 static const EnumConfigEntryItem readerWindowModes[] = {
01894   { "hide", I18N_NOOP("&Do not show a message preview pane") },
01895   { "below", I18N_NOOP("Show the message preview pane belo&w the message list") },
01896   { "right", I18N_NOOP("Show the message preview pane ne&xt to the message list") }
01897 };
01898 static const EnumConfigEntry readerWindowMode = {
01899   "Geometry", "readerWindowMode", I18N_NOOP("Message Preview Pane"),
01900   readerWindowModes, DIM(readerWindowModes), 1
01901 };
01902 
01903 AppearancePageLayoutTab::AppearancePageLayoutTab( QWidget * parent, const char * name )
01904   : ConfigModuleTab( parent, name )
01905 {
01906   // tmp. vars:
01907   QVBoxLayout * vlay;
01908 
01909   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
01910 
01911   // "folder list" radio buttons:
01912   populateButtonGroup( mFolderListGroup = new QHButtonGroup( this ), folderListMode );
01913   vlay->addWidget( mFolderListGroup );
01914   connect( mFolderListGroup, SIGNAL ( clicked( int ) ),
01915            this, SLOT( slotEmitChanged() ) );
01916 
01917   mFavoriteFolderViewCB = new QCheckBox( i18n("Show favorite folder view"), this );
01918   connect( mFavoriteFolderViewCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
01919   vlay->addWidget( mFavoriteFolderViewCB );
01920 
01921   // "show reader window" radio buttons:
01922   populateButtonGroup( mReaderWindowModeGroup = new QVButtonGroup( this ), readerWindowMode );
01923   vlay->addWidget( mReaderWindowModeGroup );
01924   connect( mReaderWindowModeGroup, SIGNAL ( clicked( int ) ),
01925            this, SLOT( slotEmitChanged() ) );
01926 
01927   // "Show MIME Tree" radio buttons:
01928   populateButtonGroup( mMIMETreeModeGroup = new QVButtonGroup( this ), mimeTreeMode );
01929   vlay->addWidget( mMIMETreeModeGroup );
01930   connect( mMIMETreeModeGroup, SIGNAL ( clicked( int ) ),
01931            this, SLOT( slotEmitChanged() ) );
01932 
01933   // "MIME Tree Location" radio buttons:
01934   populateButtonGroup( mMIMETreeLocationGroup = new QHButtonGroup( this ), mimeTreeLocation );
01935   vlay->addWidget( mMIMETreeLocationGroup );
01936   connect( mMIMETreeLocationGroup, SIGNAL ( clicked( int ) ),
01937            this, SLOT( slotEmitChanged() ) );
01938 
01939   vlay->addStretch( 10 ); // spacer
01940 }
01941 
01942 void AppearancePage::LayoutTab::doLoadOther() {
01943   const KConfigGroup reader( KMKernel::config(), "Reader" );
01944   const KConfigGroup geometry( KMKernel::config(), "Geometry" );
01945 
01946   loadWidget( mFolderListGroup, geometry, folderListMode );
01947   loadWidget( mMIMETreeLocationGroup, reader, mimeTreeLocation );
01948   loadWidget( mMIMETreeModeGroup, reader, mimeTreeMode );
01949   loadWidget( mReaderWindowModeGroup, geometry, readerWindowMode );
01950   mFavoriteFolderViewCB->setChecked( GlobalSettings::self()->enableFavoriteFolderView() );
01951 }
01952 
01953 void AppearancePage::LayoutTab::installProfile( KConfig * profile ) {
01954   const KConfigGroup reader( profile, "Reader" );
01955   const KConfigGroup geometry( profile, "Geometry" );
01956 
01957   loadProfile( mFolderListGroup, geometry, folderListMode );
01958   loadProfile( mMIMETreeLocationGroup, reader, mimeTreeLocation );
01959   loadProfile( mMIMETreeModeGroup, reader, mimeTreeMode );
01960   loadProfile( mReaderWindowModeGroup, geometry, readerWindowMode );
01961 }
01962 
01963 void AppearancePage::LayoutTab::save() {
01964   KConfigGroup reader( KMKernel::config(), "Reader" );
01965   KConfigGroup geometry( KMKernel::config(), "Geometry" );
01966 
01967   saveButtonGroup( mFolderListGroup, geometry, folderListMode );
01968   saveButtonGroup( mMIMETreeLocationGroup, reader, mimeTreeLocation );
01969   saveButtonGroup( mMIMETreeModeGroup, reader, mimeTreeMode );
01970   saveButtonGroup( mReaderWindowModeGroup, geometry, readerWindowMode );
01971   GlobalSettings::self()->setEnableFavoriteFolderView( mFavoriteFolderViewCB->isChecked() );
01972 }
01973 
01974 //
01975 // Appearance Message List
01976 //
01977 
01978 QString AppearancePage::HeadersTab::helpAnchor() const {
01979   return QString::fromLatin1("configure-appearance-headers");
01980 }
01981 
01982 static const struct {
01983   const char * displayName;
01984   DateFormatter::FormatType dateDisplay;
01985 } dateDisplayConfig[] = {
01986   { I18N_NOOP("Sta&ndard format (%1)"), KMime::DateFormatter::CTime },
01987   { I18N_NOOP("Locali&zed format (%1)"), KMime::DateFormatter::Localized },
01988   { I18N_NOOP("Fancy for&mat (%1)"), KMime::DateFormatter::Fancy },
01989   { I18N_NOOP("C&ustom format (Shift+F1 for help):"),
01990     KMime::DateFormatter::Custom }
01991 };
01992 static const int numDateDisplayConfig =
01993   sizeof dateDisplayConfig / sizeof *dateDisplayConfig;
01994 
01995 AppearancePageHeadersTab::AppearancePageHeadersTab( QWidget * parent, const char * name )
01996   : ConfigModuleTab( parent, name ),
01997     mCustomDateFormatEdit( 0 )
01998 {
01999   // tmp. vars:
02000   QButtonGroup * group;
02001   QRadioButton * radio;
02002 
02003   QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
02004 
02005   // "General Options" group:
02006   group = new QVButtonGroup( i18n( "General Options" ), this );
02007   group->layout()->setSpacing( KDialog::spacingHint() );
02008 
02009   mMessageSizeCheck = new QCheckBox( i18n("Display messa&ge sizes"), group );
02010 
02011   mCryptoIconsCheck = new QCheckBox( i18n( "Show crypto &icons" ), group );
02012 
02013   mAttachmentCheck = new QCheckBox( i18n("Show attachment icon"), group );
02014 
02015   mNestedMessagesCheck =
02016     new QCheckBox( i18n("&Threaded message list"), group );
02017 
02018   connect( mMessageSizeCheck, SIGNAL( stateChanged( int ) ),
02019            this, SLOT( slotEmitChanged( void ) ) );
02020   connect( mAttachmentCheck, SIGNAL( stateChanged( int ) ),
02021            this, SLOT( slotEmitChanged( void ) ) );
02022   connect( mCryptoIconsCheck, SIGNAL( stateChanged( int ) ),
02023            this, SLOT( slotEmitChanged( void ) ) );
02024   connect( mNestedMessagesCheck, SIGNAL( stateChanged( int ) ),
02025            this, SLOT( slotEmitChanged( void ) ) );
02026 
02027 
02028   vlay->addWidget( group );
02029 
02030   // "Message Header Threading Options" group:
02031   mNestingPolicy =
02032     new QVButtonGroup( i18n("Threaded Message List Options"), this );
02033   mNestingPolicy->layout()->setSpacing( KDialog::spacingHint() );
02034 
02035   mNestingPolicy->insert(
02036     new QRadioButton( i18n("Always &keep threads open"),
02037                       mNestingPolicy ), 0 );
02038   mNestingPolicy->insert(
02039     new QRadioButton( i18n("Threads default to o&pen"),
02040                       mNestingPolicy ), 1 );
02041   mNestingPolicy->insert(
02042     new QRadioButton( i18n("Threads default to closed"),
02043                       mNestingPolicy ), 2 );
02044   mNestingPolicy->insert(
02045     new QRadioButton( i18n("Open threads that contain ne&w, unread "
02046                            "or important messages and open watched threads."),
02047                       mNestingPolicy ), 3 );
02048 
02049   vlay->addWidget( mNestingPolicy );
02050 
02051   connect( mNestingPolicy, SIGNAL( clicked( int ) ),
02052            this, SLOT( slotEmitChanged( void ) ) );
02053 
02054   // "Date Display" group:
02055   mDateDisplay = new QVButtonGroup( i18n("Date Display"), this );
02056   mDateDisplay->layout()->setSpacing( KDialog::spacingHint() );
02057 
02058   for ( int i = 0 ; i < numDateDisplayConfig ; i++ ) {
02059     QString buttonLabel = i18n(dateDisplayConfig[i].displayName);
02060     if ( buttonLabel.contains("%1") )
02061       buttonLabel = buttonLabel.arg( DateFormatter::formatCurrentDate( dateDisplayConfig[i].dateDisplay ) );
02062     radio = new QRadioButton( buttonLabel, mDateDisplay );
02063     mDateDisplay->insert( radio, i );
02064     if ( dateDisplayConfig[i].dateDisplay == DateFormatter::Custom ) {
02065       mCustomDateFormatEdit = new KLineEdit( mDateDisplay );
02066       mCustomDateFormatEdit->setEnabled( false );
02067       connect( radio, SIGNAL(toggled(bool)),
02068                mCustomDateFormatEdit, SLOT(setEnabled(bool)) );
02069       connect( mCustomDateFormatEdit, SIGNAL(textChanged(const QString&)),
02070                this, SLOT(slotEmitChanged(void)) );
02071       QString customDateWhatsThis =
02072         i18n("<qt><p><strong>These expressions may be used for the date:"
02073              "</strong></p>"
02074              "<ul>"
02075              "<li>d - the day as a number without a leading zero (1-31)</li>"
02076              "<li>dd - the day as a number with a leading zero (01-31)</li>"
02077              "<li>ddd - the abbreviated day name (Mon - Sun)</li>"
02078              "<li>dddd - the long day name (Monday - Sunday)</li>"
02079              "<li>M - the month as a number without a leading zero (1-12)</li>"
02080              "<li>MM - the month as a number with a leading zero (01-12)</li>"
02081              "<li>MMM - the abbreviated month name (Jan - Dec)</li>"
02082              "<li>MMMM - the long month name (January - December)</li>"
02083              "<li>yy - the year as a two digit number (00-99)</li>"
02084              "<li>yyyy - the year as a four digit number (0000-9999)</li>"
02085              "</ul>"
02086              "<p><strong>These expressions may be used for the time:"
02087              "</string></p> "
02088              "<ul>"
02089              "<li>h - the hour without a leading zero (0-23 or 1-12 if AM/PM display)</li>"
02090              "<li>hh - the hour with a leading zero (00-23 or 01-12 if AM/PM display)</li>"
02091              "<li>m - the minutes without a leading zero (0-59)</li>"
02092              "<li>mm - the minutes with a leading zero (00-59)</li>"
02093              "<li>s - the seconds without a leading zero (0-59)</li>"
02094              "<li>ss - the seconds with a leading zero (00-59)</li>"
02095              "<li>z - the milliseconds without leading zeroes (0-999)</li>"
02096              "<li>zzz - the milliseconds with leading zeroes (000-999)</li>"
02097              "<li>AP - switch to AM/PM display. AP will be replaced by either \"AM\" or \"PM\".</li>"
02098              "<li>ap - switch to AM/PM display. ap will be replaced by either \"am\" or \"pm\".</li>"
02099              "<li>Z - time zone in numeric form (-0500)</li>"
02100              "</ul>"
02101              "<p><strong>All other input characters will be ignored."
02102              "</strong></p></qt>");
02103       QWhatsThis::add( mCustomDateFormatEdit, customDateWhatsThis );
02104       QWhatsThis::add( radio, customDateWhatsThis );
02105     }
02106   } // end for loop populating mDateDisplay
02107 
02108   vlay->addWidget( mDateDisplay );
02109   connect( mDateDisplay, SIGNAL( clicked( int ) ),
02110            this, SLOT( slotEmitChanged( void ) ) );
02111 
02112 
02113   vlay->addStretch( 10 ); // spacer
02114 }
02115 
02116 void AppearancePage::HeadersTab::doLoadOther() {
02117   KConfigGroup general( KMKernel::config(), "General" );
02118   KConfigGroup geometry( KMKernel::config(), "Geometry" );
02119 
02120   // "General Options":
02121   mNestedMessagesCheck->setChecked( geometry.readBoolEntry( "nestedMessages", false ) );
02122   mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize", false ) );
02123   mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons", false ) );
02124   mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon", true ) );
02125 
02126   // "Message Header Threading Options":
02127   int num = geometry.readNumEntry( "nestingPolicy", 3 );
02128   if ( num < 0 || num > 3 ) num = 3;
02129   mNestingPolicy->setButton( num );
02130 
02131   // "Date Display":
02132   setDateDisplay( general.readNumEntry( "dateFormat", DateFormatter::Fancy ),
02133                   general.readEntry( "customDateFormat" ) );
02134 }
02135 
02136 void AppearancePage::HeadersTab::setDateDisplay( int num, const QString & format ) {
02137   DateFormatter::FormatType dateDisplay =
02138     static_cast<DateFormatter::FormatType>( num );
02139 
02140   // special case: needs text for the line edit:
02141   if ( dateDisplay == DateFormatter::Custom )
02142     mCustomDateFormatEdit->setText( format );
02143 
02144   for ( int i = 0 ; i < numDateDisplayConfig ; i++ )
02145     if ( dateDisplay == dateDisplayConfig[i].dateDisplay ) {
02146       mDateDisplay->setButton( i );
02147       return;
02148     }
02149   // fell through since none found:
02150   mDateDisplay->setButton( numDateDisplayConfig - 2 ); // default
02151 }
02152 
02153 void AppearancePage::HeadersTab::installProfile( KConfig * profile ) {
02154   KConfigGroup general( profile, "General" );
02155   KConfigGroup geometry( profile, "Geometry" );
02156 
02157   if ( geometry.hasKey( "nestedMessages" ) )
02158     mNestedMessagesCheck->setChecked( geometry.readBoolEntry( "nestedMessages" ) );
02159   if ( general.hasKey( "showMessageSize" ) )
02160     mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize" ) );
02161 
02162   if( general.hasKey( "showCryptoIcons" ) )
02163     mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons" ) );
02164   if ( general.hasKey( "showAttachmentIcon" ) )
02165     mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon" ) );
02166 
02167   if ( geometry.hasKey( "nestingPolicy" ) ) {
02168     int num = geometry.readNumEntry( "nestingPolicy" );
02169     if ( num < 0 || num > 3 ) num = 3;
02170     mNestingPolicy->setButton( num );
02171   }
02172 
02173   if ( general.hasKey( "dateFormat" ) )
02174     setDateDisplay( general.readNumEntry( "dateFormat" ),
02175                    general.readEntry( "customDateFormat" ) );
02176 }
02177 
02178 void AppearancePage::HeadersTab::save() {
02179   KConfigGroup general( KMKernel::config(), "General" );
02180   KConfigGroup geometry( KMKernel::config(), "Geometry" );
02181 
02182   if ( geometry.readBoolEntry( "nestedMessages", false )
02183        != mNestedMessagesCheck->isChecked() ) {
02184     int result = KMessageBox::warningContinueCancel( this,
02185                    i18n("Changing the global threading setting will override "
02186                         "all folder specific values."),
02187                    QString::null, KStdGuiItem::cont(), "threadOverride" );
02188     if ( result == KMessageBox::Continue ) {
02189       geometry.writeEntry( "nestedMessages", mNestedMessagesCheck->isChecked() );
02190       // remove all threadMessagesOverride keys from all [Folder-*] groups:
02191       QStringList groups = KMKernel::config()->groupList().grep( QRegExp("^Folder-") );
02192       kdDebug(5006) << "groups.count() == " << groups.count() << endl;
02193       for ( QStringList::const_iterator it = groups.begin() ; it != groups.end() ; ++it ) {
02194         KConfigGroup group( KMKernel::config(), *it );
02195         group.deleteEntry( "threadMessagesOverride" );
02196       }
02197     }
02198   }
02199 
02200   geometry.writeEntry( "nestingPolicy",
02201                        mNestingPolicy->id( mNestingPolicy->selected() ) );
02202   general.writeEntry( "showMessageSize", mMessageSizeCheck->isChecked() );
02203   general.writeEntry( "showCryptoIcons", mCryptoIconsCheck->isChecked() );
02204   general.writeEntry( "showAttachmentIcon", mAttachmentCheck->isChecked() );
02205 
02206   int dateDisplayID = mDateDisplay->id( mDateDisplay->selected() );
02207   // check bounds:
02208   assert( dateDisplayID >= 0 ); assert( dateDisplayID < numDateDisplayConfig );
02209   general.writeEntry( "dateFormat",
02210                       dateDisplayConfig[ dateDisplayID ].dateDisplay );
02211   general.writeEntry( "customDateFormat", mCustomDateFormatEdit->text() );
02212 }
02213 
02214 
02215 //
02216 // Message Window
02217 //
02218 
02219 
02220 static const BoolConfigEntry closeAfterReplyOrForward = {
02221   "Reader", "CloseAfterReplyOrForward", I18N_NOOP("Close message window after replying or forwarding"), false
02222 };
02223 
02224 static const BoolConfigEntry showColorbarMode = {
02225   "Reader", "showColorbar", I18N_NOOP("Show HTML stat&us bar"), false
02226 };
02227 
02228 static const BoolConfigEntry showSpamStatusMode = {
02229   "Reader", "showSpamStatus", I18N_NOOP("Show s&pam status in fancy headers"), true
02230 };
02231 
02232 static const BoolConfigEntry showEmoticons = {
02233   "Reader", "ShowEmoticons", I18N_NOOP("Replace smileys by emoticons"), true
02234 };
02235 
02236 static const BoolConfigEntry shrinkQuotes = {
02237   "Reader", "ShrinkQuotes", I18N_NOOP("Use smaller font for quoted text"), false
02238 };
02239 
02240 static const BoolConfigEntry showExpandQuotesMark= {
02241   "Reader", "ShowExpandQuotesMark", I18N_NOOP("Show expand/collapse quote marks"), false
02242 };
02243 
02244 
02245 QString AppearancePage::ReaderTab::helpAnchor() const {
02246   return QString::fromLatin1("configure-appearance-reader");
02247 }
02248 
02249 AppearancePageReaderTab::AppearancePageReaderTab( QWidget * parent,
02250                                                   const char * name )
02251   : ConfigModuleTab( parent, name )
02252 {
02253   QVBoxLayout *vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
02254 
02255   // "close message window after replying or forwarding" checkbox
02256   populateCheckBox( mCloseAfterReplyOrForwardCheck = new QCheckBox( this ),
02257                     closeAfterReplyOrForward );
02258   QToolTip::add( mCloseAfterReplyOrForwardCheck,
02259                  i18n( "Close the standalone message window after replying or forwarding the message" ) );
02260   vlay->addWidget( mCloseAfterReplyOrForwardCheck );
02261   connect( mCloseAfterReplyOrForwardCheck, SIGNAL ( stateChanged( int ) ),
02262            this, SLOT( slotEmitChanged() ) );
02263 
02264   // "show colorbar" check box:
02265   populateCheckBox( mShowColorbarCheck = new QCheckBox( this ), showColorbarMode );
02266   vlay->addWidget( mShowColorbarCheck );
02267   connect( mShowColorbarCheck, SIGNAL ( stateChanged( int ) ),
02268            this, SLOT( slotEmitChanged() ) );
02269 
02270   // "show spam status" check box;
02271   populateCheckBox( mShowSpamStatusCheck = new QCheckBox( this ), showSpamStatusMode );
02272   vlay->addWidget( mShowSpamStatusCheck );
02273   connect( mShowSpamStatusCheck, SIGNAL ( stateChanged( int ) ),
02274            this, SLOT( slotEmitChanged() ) );
02275 
02276   // "replace smileys by emoticons" check box;
02277   populateCheckBox( mShowEmoticonsCheck = new QCheckBox( this ), showEmoticons );
02278   vlay->addWidget( mShowEmoticonsCheck );
02279   connect( mShowEmoticonsCheck, SIGNAL ( stateChanged( int ) ),
02280            this, SLOT( slotEmitChanged() ) );
02281 
02282   // "Use smaller font for quoted text" check box
02283   mShrinkQuotesCheck = new QCheckBox( i18n( shrinkQuotes.desc ), this,
02284                                       "kcfg_ShrinkQuotes" );
02285   vlay->addWidget( mShrinkQuotesCheck );
02286   connect( mShrinkQuotesCheck, SIGNAL( stateChanged( int ) ),
02287            this, SLOT( slotEmitChanged() ) );
02288 
02289   // "Show expand/collaps quote marks" check box;
02290   QHBoxLayout *hlay= new QHBoxLayout( vlay ); // inherits spacing
02291   populateCheckBox( mShowExpandQuotesMark= new QCheckBox( this ), showExpandQuotesMark);
02292   hlay->addWidget( mShowExpandQuotesMark);
02293   connect( mShowExpandQuotesMark, SIGNAL ( stateChanged( int ) ),
02294            this, SLOT( slotEmitChanged() ) );
02295 
02296   hlay->addStretch( 1 );
02297   mCollapseQuoteLevelSpin = new KIntSpinBox( 0/*min*/,10/*max*/,1/*step*/,
02298       3/*init*/,10/*base*/,this );
02299 
02300   QLabel *label = new QLabel( mCollapseQuoteLevelSpin,
02301            GlobalSettings::self()->collapseQuoteLevelSpinItem()->label(), this );
02302 
02303   hlay->addWidget( label );
02304 
02305   mCollapseQuoteLevelSpin->setEnabled( false ); //since !mShowExpandQuotesMark->isCheckec()
02306   connect(  mCollapseQuoteLevelSpin, SIGNAL( valueChanged( int ) ),
02307       this, SLOT( slotEmitChanged( void ) ) );
02308   hlay->addWidget( mCollapseQuoteLevelSpin);
02309 
02310   connect( mShowExpandQuotesMark, SIGNAL( toggled( bool ) ),
02311       mCollapseQuoteLevelSpin, SLOT( setEnabled( bool ) ) );
02312 
02313   // Fallback Character Encoding
02314   hlay = new QHBoxLayout( vlay ); // inherits spacing
02315   mCharsetCombo = new QComboBox( this );
02316   mCharsetCombo->insertStringList( KMMsgBase::supportedEncodings( false ) );
02317 
02318   connect( mCharsetCombo, SIGNAL( activated( int ) ),
02319            this, SLOT( slotEmitChanged( void ) ) );
02320 
02321   QString fallbackCharsetWhatsThis =
02322     i18n( GlobalSettings::self()->fallbackCharacterEncodingItem()->whatsThis().utf8() );
02323   QWhatsThis::add( mCharsetCombo, fallbackCharsetWhatsThis );
02324 
02325   label = new QLabel( i18n("Fallback ch&aracter encoding:"), this );
02326   label->setBuddy( mCharsetCombo );
02327 
02328   hlay->addWidget( label );
02329   hlay->addWidget( mCharsetCombo );
02330 
02331   // Override Character Encoding
02332   QHBoxLayout *hlay2 = new QHBoxLayout( vlay ); // inherits spacing
02333   mOverrideCharsetCombo = new QComboBox( this );
02334   QStringList encodings = KMMsgBase::supportedEncodings( false );
02335   encodings.prepend( i18n( "Auto" ) );
02336   mOverrideCharsetCombo->insertStringList( encodings );
02337   mOverrideCharsetCombo->setCurrentItem(0);
02338 
02339   connect( mOverrideCharsetCombo, SIGNAL( activated( int ) ),
02340            this, SLOT( slotEmitChanged( void ) ) );
02341 
02342   QString overrideCharsetWhatsThis =
02343     i18n( GlobalSettings::self()->overrideCharacterEncodingItem()->whatsThis().utf8() );
02344   QWhatsThis::add( mOverrideCharsetCombo, overrideCharsetWhatsThis );
02345 
02346   label = new QLabel( i18n("&Override character encoding:"), this );
02347   label->setBuddy( mOverrideCharsetCombo );
02348 
02349   hlay2->addWidget( label );
02350   hlay2->addWidget( mOverrideCharsetCombo );
02351 
02352   vlay->addStretch( 100 ); // spacer
02353 }
02354 
02355 
02356 void AppearancePage::ReaderTab::readCurrentFallbackCodec()
02357 {
02358   QStringList encodings = KMMsgBase::supportedEncodings( false );
02359   QStringList::ConstIterator it( encodings.begin() );
02360   QStringList::ConstIterator end( encodings.end() );
02361   QString currentEncoding = GlobalSettings::self()->fallbackCharacterEncoding();
02362   currentEncoding = currentEncoding.replace( "iso ", "iso-", false );
02364   int i = 0;
02365   int indexOfLatin9 = 0;
02366   bool found = false;
02367   for( ; it != end; ++it)
02368   {
02369     const QString encoding = KGlobal::charsets()->encodingForName(*it);
02370     if ( encoding == "iso-8859-15" )
02371         indexOfLatin9 = i;
02372     if( encoding == currentEncoding )
02373     {
02374       mCharsetCombo->setCurrentItem( i );
02375       found = true;
02376       break;
02377     }
02378     i++;
02379   }
02380   if ( !found ) // nothing matched, use latin9
02381     mCharsetCombo->setCurrentItem( indexOfLatin9 );
02382 }
02383 
02384 void AppearancePage::ReaderTab::readCurrentOverrideCodec()
02385 {
02386   const QString &currentOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding();
02387   if ( currentOverrideEncoding.isEmpty() ) {
02388     mOverrideCharsetCombo->setCurrentItem( 0 );
02389     return;
02390   }
02391   QStringList encodings = KMMsgBase::supportedEncodings( false );
02392   encodings.prepend( i18n( "Auto" ) );
02393   QStringList::Iterator it( encodings.begin() );
02394   QStringList::Iterator end( encodings.end() );
02395   uint i = 0;
02396   for( ; it != end; ++it)
02397   {
02398     if( KGlobal::charsets()->encodingForName(*it) == currentOverrideEncoding )
02399     {
02400       mOverrideCharsetCombo->setCurrentItem( i );
02401       break;
02402     }
02403     i++;
02404   }
02405   if ( i == encodings.size() ) {
02406     // the current value of overrideCharacterEncoding is an unknown encoding => reset to Auto
02407     kdWarning(5006) << "Unknown override character encoding \"" << currentOverrideEncoding
02408                     << "\". Resetting to Auto." << endl;
02409     mOverrideCharsetCombo->setCurrentItem( 0 );
02410     GlobalSettings::self()->setOverrideCharacterEncoding( QString::null );
02411   }
02412 }
02413 
02414 void AppearancePage::ReaderTab::doLoadFromGlobalSettings()
02415 {
02416   mCloseAfterReplyOrForwardCheck->setChecked( GlobalSettings::self()->closeAfterReplyOrForward() );
02417   mShowEmoticonsCheck->setChecked( GlobalSettings::self()->showEmoticons() );
02418   mShrinkQuotesCheck->setChecked( GlobalSettings::self()->shrinkQuotes() );
02419   mShowExpandQuotesMark->setChecked( GlobalSettings::self()->showExpandQuotesMark() );
02420   mCollapseQuoteLevelSpin->setValue( GlobalSettings::self()->collapseQuoteLevelSpin() );
02421   readCurrentFallbackCodec();
02422   readCurrentOverrideCodec();
02423 }
02424 
02425 void AppearancePage::ReaderTab::doLoadOther()
02426 {
02427   const KConfigGroup reader( KMKernel::config(), "Reader" );
02428   loadWidget( mShowColorbarCheck, reader, showColorbarMode );
02429   loadWidget( mShowSpamStatusCheck, reader, showSpamStatusMode );
02430 }
02431 
02432 
02433 void AppearancePage::ReaderTab::save() {
02434   KConfigGroup reader( KMKernel::config(), "Reader" );
02435   saveCheckBox( mShowColorbarCheck, reader, showColorbarMode );
02436   saveCheckBox( mShowSpamStatusCheck, reader, showSpamStatusMode );
02437   GlobalSettings::self()->setCloseAfterReplyOrForward( mCloseAfterReplyOrForwardCheck->isChecked() );
02438   GlobalSettings::self()->setShowEmoticons( mShowEmoticonsCheck->isChecked() );
02439   GlobalSettings::self()->setShrinkQuotes( mShrinkQuotesCheck->isChecked() );
02440   GlobalSettings::self()->setShowExpandQuotesMark( mShowExpandQuotesMark->isChecked() );
02441 
02442   GlobalSettings::self()->setCollapseQuoteLevelSpin( mCollapseQuoteLevelSpin->value() );
02443   GlobalSettings::self()->setFallbackCharacterEncoding(
02444       KGlobal::charsets()->encodingForName( mCharsetCombo->currentText() ) );
02445   GlobalSettings::self()->setOverrideCharacterEncoding(
02446       mOverrideCharsetCombo->currentItem() == 0 ?
02447         QString() :
02448         KGlobal::charsets()->encodingForName( mOverrideCharsetCombo->currentText() ) );
02449 }
02450 
02451 
02452 void AppearancePage::ReaderTab::installProfile( KConfig * /* profile */ ) {
02453   const KConfigGroup reader( KMKernel::config(), "Reader" );
02454   loadProfile( mCloseAfterReplyOrForwardCheck, reader, closeAfterReplyOrForward );
02455   loadProfile( mShowColorbarCheck, reader, showColorbarMode );
02456   loadProfile( mShowSpamStatusCheck, reader, showSpamStatusMode );
02457   loadProfile( mShowEmoticonsCheck, reader, showEmoticons );
02458   loadProfile( mShrinkQuotesCheck, reader, shrinkQuotes );
02459   loadProfile( mShowExpandQuotesMark, reader, showExpandQuotesMark);
02460 }
02461 
02462 
02463 QString AppearancePage::SystemTrayTab::helpAnchor() const {
02464   return QString::fromLatin1("configure-appearance-systemtray");
02465 }
02466 
02467 AppearancePageSystemTrayTab::AppearancePageSystemTrayTab( QWidget * parent,
02468                                                           const char * name )
02469   : ConfigModuleTab( parent, name )
02470 {
02471   QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(),
02472                                         KDialog::spacingHint() );
02473 
02474   // "Enable system tray applet" check box
02475   mSystemTrayCheck = new QCheckBox( i18n("Enable system tray icon"), this );
02476   vlay->addWidget( mSystemTrayCheck );
02477   connect( mSystemTrayCheck, SIGNAL( stateChanged( int ) ),
02478            this, SLOT( slotEmitChanged( void ) ) );
02479 
02480   // System tray modes
02481   mSystemTrayGroup = new QVButtonGroup( i18n("System Tray Mode"), this );
02482   mSystemTrayGroup->layout()->setSpacing( KDialog::spacingHint() );
02483   vlay->addWidget( mSystemTrayGroup );
02484   connect( mSystemTrayGroup, SIGNAL( clicked( int ) ),
02485            this, SLOT( slotEmitChanged( void ) ) );
02486   connect( mSystemTrayCheck, SIGNAL( toggled( bool ) ),
02487            mSystemTrayGroup, SLOT( setEnabled( bool ) ) );
02488 
02489   mSystemTrayGroup->insert( new QRadioButton( i18n("Always show KMail in system tray"), mSystemTrayGroup ),
02490                             GlobalSettings::EnumSystemTrayPolicy::ShowAlways );
02491 
02492   mSystemTrayGroup->insert( new QRadioButton( i18n("Only show KMail in system tray if there are unread messages"), mSystemTrayGroup ),
02493                             GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread );
02494 
02495   vlay->addStretch( 10 ); // spacer
02496 }
02497 
02498 void AppearancePage::SystemTrayTab::doLoadFromGlobalSettings() {
02499   mSystemTrayCheck->setChecked( GlobalSettings::self()->systemTrayEnabled() );
02500   mSystemTrayGroup->setButton( GlobalSettings::self()->systemTrayPolicy() );
02501   mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() );
02502 }
02503 
02504 void AppearancePage::SystemTrayTab::installProfile( KConfig * profile ) {
02505   KConfigGroup general( profile, "General" );
02506 
02507   if ( general.hasKey( "SystemTrayEnabled" ) ) {
02508     mSystemTrayCheck->setChecked( general.readBoolEntry( "SystemTrayEnabled" ) );
02509   }
02510   if ( general.hasKey( "SystemTrayPolicy" ) ) {
02511     mSystemTrayGroup->setButton( general.readNumEntry( "SystemTrayPolicy" ) );
02512   }
02513   mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() );
02514 }
02515 
02516 void AppearancePage::SystemTrayTab::save() {
02517   GlobalSettings::self()->setSystemTrayEnabled( mSystemTrayCheck->isChecked() );
02518   GlobalSettings::self()->setSystemTrayPolicy( mSystemTrayGroup->id( mSystemTrayGroup->selected() ) );
02519 }
02520 
02521 
02522 // *************************************************************
02523 // *                                                           *
02524 // *                      ComposerPage                         *
02525 // *                                                           *
02526 // *************************************************************
02527 
02528 QString ComposerPage::helpAnchor() const {
02529   return QString::fromLatin1("configure-composer");
02530 }
02531 
02532 ComposerPage::ComposerPage( QWidget * parent, const char * name )
02533   : ConfigModuleWithTabs( parent, name )
02534 {
02535   //
02536   // "General" tab:
02537   //
02538   mGeneralTab = new GeneralTab();
02539   addTab( mGeneralTab, i18n("&General") );
02540   addConfig( GlobalSettings::self(), mGeneralTab );
02541 
02542   //
02543   // "Phrases" tab:
02544   //
02545   // mPhrasesTab = new PhrasesTab();
02546   // addTab( mPhrasesTab, i18n("&Phrases") );
02547 
02548   //
02549   // "Templates" tab:
02550   //
02551   mTemplatesTab = new TemplatesTab();
02552   addTab( mTemplatesTab, i18n("&Templates") );
02553 
02554   //
02555   // "Custom Templates" tab:
02556   //
02557   mCustomTemplatesTab = new CustomTemplatesTab();
02558   addTab( mCustomTemplatesTab, i18n("&Custom Templates") );
02559 
02560   //
02561   // "Subject" tab:
02562   //
02563   mSubjectTab = new SubjectTab();
02564   addTab( mSubjectTab, i18n("&Subject") );
02565   addConfig( GlobalSettings::self(), mSubjectTab );
02566 
02567   //
02568   // "Charset" tab:
02569   //
02570   mCharsetTab = new CharsetTab();
02571   addTab( mCharsetTab, i18n("Cha&rset") );
02572 
02573   //
02574   // "Headers" tab:
02575   //
02576   mHeadersTab = new HeadersTab();
02577   addTab( mHeadersTab, i18n("H&eaders") );
02578 
02579   //
02580   // "Attachments" tab:
02581   //
02582   mAttachmentsTab = new AttachmentsTab();
02583   addTab( mAttachmentsTab, i18n("Config->Composer->Attachments", "A&ttachments") );
02584   load();
02585 }
02586 
02587 QString ComposerPage::GeneralTab::helpAnchor() const {
02588   return QString::fromLatin1("configure-composer-general");
02589 }
02590 
02591 ComposerPageGeneralTab::ComposerPageGeneralTab( QWidget * parent, const char * name )
02592   : ConfigModuleTab( parent, name )
02593 {
02594   // tmp. vars:
02595   QVBoxLayout *vlay;
02596   QHBoxLayout *hlay;
02597   QGroupBox   *group;
02598   QLabel      *label;
02599   QHBox       *hbox;
02600   QString      msg;
02601 
02602   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
02603 
02604   // some check buttons...
02605   mAutoAppSignFileCheck = new QCheckBox(
02606            GlobalSettings::self()->autoTextSignatureItem()->label(),
02607            this );
02608   vlay->addWidget( mAutoAppSignFileCheck );
02609   connect( mAutoAppSignFileCheck, SIGNAL( stateChanged(int) ),
02610            this, SLOT( slotEmitChanged( void ) ) );
02611 
02612   mTopQuoteCheck =
02613     new QCheckBox( GlobalSettings::self()->prependSignatureItem()->label(), this );
02614   vlay->addWidget( mTopQuoteCheck);
02615   connect( mTopQuoteCheck, SIGNAL( stateChanged(int) ),
02616            this, SLOT( slotEmitChanged( void ) ) );
02617 
02618   mSmartQuoteCheck = new QCheckBox(
02619            GlobalSettings::self()->smartQuoteItem()->label(),
02620            this, "kcfg_SmartQuote" );
02621   QToolTip::add( mSmartQuoteCheck,
02622                  i18n( "When replying, add quote signs in front of all lines of the quoted text,\n"
02623                        "even when the line was created by adding an additional linebreak while\n"
02624                        "word-wrapping the text." ) );
02625   vlay->addWidget( mSmartQuoteCheck );
02626   connect( mSmartQuoteCheck, SIGNAL( stateChanged(int) ),
02627            this, SLOT( slotEmitChanged( void ) ) );
02628 
02629   mQuoteSelectionOnlyCheck = new QCheckBox( GlobalSettings::self()->quoteSelectionOnlyItem()->label(),
02630                                             this, "kcfg_QuoteSelectionOnly" );
02631   QToolTip::add( mQuoteSelectionOnlyCheck,
02632                  i18n( "When replying, only quote the selected text instead of the complete message "
02633                        "when there is text selected in the message window." ) );
02634   vlay->addWidget( mQuoteSelectionOnlyCheck );
02635   connect( mQuoteSelectionOnlyCheck, SIGNAL( stateChanged(int) ),
02636            this, SLOT( slotEmitChanged(void) ) );
02637 
02638   mStripSignatureCheck = new QCheckBox( GlobalSettings::self()->stripSignatureItem()->label(),
02639                                         this, "kcfg_StripSignature" );
02640   vlay->addWidget( mStripSignatureCheck );
02641   connect( mStripSignatureCheck, SIGNAL( stateChanged(int) ),
02642            this, SLOT( slotEmitChanged( void ) ) );
02643 
02644   mAutoRequestMDNCheck = new QCheckBox(
02645            GlobalSettings::self()->requestMDNItem()->label(),
02646            this, "kcfg_RequestMDN" );
02647   vlay->addWidget( mAutoRequestMDNCheck );
02648   connect( mAutoRequestMDNCheck, SIGNAL( stateChanged(int) ),
02649            this, SLOT( slotEmitChanged( void ) ) );
02650 
02651   mShowRecentAddressesInComposer = new QCheckBox(
02652            GlobalSettings::self()->showRecentAddressesInComposerItem()->label(),
02653            this, "kcfg_ShowRecentAddressesInComposer" );
02654   vlay->addWidget( mShowRecentAddressesInComposer );
02655   connect( mShowRecentAddressesInComposer, SIGNAL( stateChanged(int) ),
02656            this, SLOT( slotEmitChanged( void ) ) );
02657 
02658   // a checkbox for "word wrap" and a spinbox for the column in
02659   // which to wrap:
02660   hlay = new QHBoxLayout( vlay ); // inherits spacing
02661   mWordWrapCheck = new QCheckBox(
02662            GlobalSettings::self()->wordWrapItem()->label(),
02663            this, "kcfg_WordWrap" );
02664   hlay->addWidget( mWordWrapCheck );
02665   connect( mWordWrapCheck, SIGNAL( stateChanged(int) ),
02666            this, SLOT( slotEmitChanged( void ) ) );
02667 
02668   mWrapColumnSpin = new KIntSpinBox( 30/*min*/, 78/*max*/, 1/*step*/,
02669            78/*init*/, 10 /*base*/, this, "kcfg_LineWrapWidth" );
02670   mWrapColumnSpin->setEnabled( false ); // since !mWordWrapCheck->isChecked()
02671   connect( mWrapColumnSpin, SIGNAL( valueChanged(int) ),
02672            this, SLOT( slotEmitChanged( void ) ) );
02673 
02674   hlay->addWidget( mWrapColumnSpin );
02675   hlay->addStretch( 1 );
02676   // only enable the spinbox if the checkbox is checked:
02677   connect( mWordWrapCheck, SIGNAL(toggled(bool)),
02678            mWrapColumnSpin, SLOT(setEnabled(bool)) );
02679 
02680   // a checkbox for "too many recipient warning" and a spinbox for the recipient threshold
02681   hlay = new QHBoxLayout( vlay ); // inherits spacing
02682   mRecipientCheck = new QCheckBox(
02683            GlobalSettings::self()->tooManyRecipientsItem()->label(),
02684            this, "kcfg_TooManyRecipients" );
02685   hlay->addWidget( mRecipientCheck );
02686   connect( mRecipientCheck, SIGNAL( stateChanged(int) ),
02687            this, SLOT( slotEmitChanged( void ) ) );
02688 
02689   QString recipientCheckWhatsthis =
02690     i18n( GlobalSettings::self()->tooManyRecipientsItem()->whatsThis().utf8() );
02691   QWhatsThis::add( mRecipientCheck, recipientCheckWhatsthis );
02692   QToolTip::add( mRecipientCheck,
02693                  i18n( "Warn if too many recipients are specified" ) );
02694 
02695   mRecipientSpin = new KIntSpinBox( 1/*min*/, 100/*max*/, 1/*step*/,
02696            5/*init*/, 10 /*base*/, this, "kcfg_RecipientThreshold" );
02697   mRecipientSpin->setEnabled( false );
02698   connect( mRecipientSpin, SIGNAL( valueChanged(int) ),
02699            this, SLOT( slotEmitChanged( void ) ) );
02700 
02701   QString recipientWhatsthis =
02702     i18n( GlobalSettings::self()->recipientThresholdItem()->whatsThis().utf8() );
02703   QWhatsThis::add( mRecipientSpin, recipientWhatsthis );
02704   QToolTip::add( mRecipientSpin,
02705                  i18n( "Warn if more than this many recipients are specified" ) );
02706 
02707 
02708   hlay->addWidget( mRecipientSpin );
02709   hlay->addStretch( 1 );
02710   // only enable the spinbox if the checkbox is checked:
02711   connect( mRecipientCheck, SIGNAL(toggled(bool)),
02712            mRecipientSpin, SLOT(setEnabled(bool)) );
02713 
02714 
02715   hlay = new QHBoxLayout( vlay ); // inherits spacing
02716   mAutoSave = new KIntSpinBox( 0, 60, 1, 1, 10, this, "kcfg_AutosaveInterval" );
02717   label = new QLabel( mAutoSave,
02718            GlobalSettings::self()->autosaveIntervalItem()->label(), this );
02719   hlay->addWidget( label );
02720   hlay->addWidget( mAutoSave );
02721   mAutoSave->setSpecialValueText( i18n("No autosave") );
02722   mAutoSave->setSuffix( i18n(" min") );
02723   hlay->addStretch( 1 );
02724   connect( mAutoSave, SIGNAL( valueChanged(int) ),
02725            this, SLOT( slotEmitChanged( void ) ) );
02726 
02727   hlay = new QHBoxLayout( vlay ); // inherits spacing
02728   mForwardTypeCombo = new KComboBox( false, this );
02729   label = new QLabel( mForwardTypeCombo,
02730                       i18n( "Default Forwarding Type:" ),
02731                       this );
02732   mForwardTypeCombo->insertStringList( QStringList()
02733                                        << i18n( "Inline" )
02734                                        << i18n( "As Attachment" ) );
02735   hlay->addWidget( label );
02736   hlay->addWidget( mForwardTypeCombo );
02737   hlay->addStretch( 1 );
02738   connect( mForwardTypeCombo, SIGNAL(activated(int)),
02739            this, SLOT( slotEmitChanged( void ) ) );
02740 
02741   hlay = new QHBoxLayout( vlay ); // inherits spacing
02742   QPushButton *completionOrderBtn = new QPushButton( i18n( "Configure Completion Order" ), this );
02743   connect( completionOrderBtn, SIGNAL( clicked() ),
02744            this, SLOT( slotConfigureCompletionOrder() ) );
02745   hlay->addWidget( completionOrderBtn );
02746   hlay->addItem( new QSpacerItem(0, 0) );
02747 
02748   // recent addresses
02749   hlay = new QHBoxLayout( vlay ); // inherits spacing
02750   QPushButton *recentAddressesBtn = new QPushButton( i18n( "Edit Recent Addresses..." ), this );
02751   connect( recentAddressesBtn, SIGNAL( clicked() ),
02752            this, SLOT( slotConfigureRecentAddresses() ) );
02753   hlay->addWidget( recentAddressesBtn );
02754   hlay->addItem( new QSpacerItem(0, 0) );
02755 
02756   // The "external editor" group:
02757   group = new QVGroupBox( i18n("External Editor"), this );
02758   group->layout()->setSpacing( KDialog::spacingHint() );
02759 
02760   mExternalEditorCheck = new QCheckBox(
02761            GlobalSettings::self()->useExternalEditorItem()->label(),
02762            group, "kcfg_UseExternalEditor" );
02763   connect( mExternalEditorCheck, SIGNAL( toggled( bool ) ),
02764            this, SLOT( slotEmitChanged( void ) ) );
02765 
02766   hbox = new QHBox( group );
02767   label = new QLabel( GlobalSettings::self()->externalEditorItem()->label(),
02768                    hbox );
02769   mEditorRequester = new KURLRequester( hbox, "kcfg_ExternalEditor" );
02770   connect( mEditorRequester, SIGNAL( urlSelected(const QString&) ),
02771            this, SLOT( slotEmitChanged( void ) ) );
02772   connect( mEditorRequester, SIGNAL( textChanged(const QString&) ),
02773            this, SLOT( slotEmitChanged( void ) ) );
02774 
02775   hbox->setStretchFactor( mEditorRequester, 1 );
02776   label->setBuddy( mEditorRequester );
02777   label->setEnabled( false ); // since !mExternalEditorCheck->isChecked()
02778   // ### FIXME: allow only executables (x-bit when available..)
02779   mEditorRequester->setFilter( "application/x-executable "
02780                                "application/x-shellscript "
02781                                "application/x-desktop" );
02782   mEditorRequester->setEnabled( false ); // !mExternalEditorCheck->isChecked()
02783   connect( mExternalEditorCheck, SIGNAL(toggled(bool)),
02784            label, SLOT(setEnabled(bool)) );
02785   connect( mExternalEditorCheck, SIGNAL(toggled(bool)),
02786            mEditorRequester, SLOT(setEnabled(bool)) );
02787 
02788   label = new QLabel( i18n("<b>%f</b> will be replaced with the "
02789                            "filename to edit."), group );
02790   label->setEnabled( false ); // see above
02791   connect( mExternalEditorCheck, SIGNAL(toggled(bool)),
02792            label, SLOT(setEnabled(bool)) );
02793 
02794   vlay->addWidget( group );
02795   vlay->addStretch( 100 );
02796 }
02797 
02798 void ComposerPage::GeneralTab::doLoadFromGlobalSettings() {
02799   // various check boxes:
02800 
02801   mAutoAppSignFileCheck->setChecked(
02802            GlobalSettings::self()->autoTextSignature()=="auto" );
02803   mTopQuoteCheck->setChecked( GlobalSettings::self()->prependSignature() );
02804   mSmartQuoteCheck->setChecked( GlobalSettings::self()->smartQuote() );
02805   mQuoteSelectionOnlyCheck->setChecked( GlobalSettings::self()->quoteSelectionOnly() );
02806   mStripSignatureCheck->setChecked( GlobalSettings::self()->stripSignature() );
02807   mAutoRequestMDNCheck->setChecked( GlobalSettings::self()->requestMDN() );
02808   mWordWrapCheck->setChecked( GlobalSettings::self()->wordWrap() );
02809 
02810   mWrapColumnSpin->setValue( GlobalSettings::self()->lineWrapWidth() );
02811   mRecipientCheck->setChecked( GlobalSettings::self()->tooManyRecipients() );
02812   mRecipientSpin->setValue( GlobalSettings::self()->recipientThreshold() );
02813   mAutoSave->setValue( GlobalSettings::self()->autosaveInterval() );
02814   if ( GlobalSettings::self()->forwardingInlineByDefault() )
02815     mForwardTypeCombo->setCurrentItem( 0 );
02816   else
02817     mForwardTypeCombo->setCurrentItem( 1 );
02818 
02819   // editor group:
02820   mExternalEditorCheck->setChecked( GlobalSettings::self()->useExternalEditor() );
02821   mEditorRequester->setURL( GlobalSettings::self()->externalEditor() );
02822 }
02823 
02824 void ComposerPage::GeneralTab::installProfile( KConfig * profile ) {
02825   KConfigGroup composer( profile, "Composer" );
02826   KConfigGroup general( profile, "General" );
02827 
02828   if ( composer.hasKey( "signature" ) ) {
02829     bool state = composer.readBoolEntry("signature");
02830     mAutoAppSignFileCheck->setChecked( state );
02831   }
02832   if ( composer.hasKey( "prepend-signature" ) )
02833     mTopQuoteCheck->setChecked( composer.readBoolEntry( "prepend-signature" ) );
02834   if ( composer.hasKey( "smart-quote" ) )
02835     mSmartQuoteCheck->setChecked( composer.readBoolEntry( "smart-quote" ) );
02836   if ( composer.hasKey( "StripSignature" ) )
02837     mStripSignatureCheck->setChecked( composer.readBoolEntry( "StripSignature" ) );
02838   if ( composer.hasKey( "QuoteSelectionOnly" ) )
02839     mQuoteSelectionOnlyCheck->setChecked( composer.readBoolEntry( "QuoteSelectionOnly" ) );
02840   if ( composer.hasKey( "request-mdn" ) )
02841     mAutoRequestMDNCheck->setChecked( composer.readBoolEntry( "request-mdn" ) );
02842   if ( composer.hasKey( "word-wrap" ) )
02843     mWordWrapCheck->setChecked( composer.readBoolEntry( "word-wrap" ) );
02844   if ( composer.hasKey( "break-at" ) )
02845     mWrapColumnSpin->setValue( composer.readNumEntry( "break-at" ) );
02846   if ( composer.hasKey( "too-many-recipients" ) )
02847     mRecipientCheck->setChecked( composer.readBoolEntry( "too-many-recipients" ) );
02848   if ( composer.hasKey( "recipient-threshold" ) )
02849     mRecipientSpin->setValue( composer.readNumEntry( "recipient-threshold" ) );
02850   if ( composer.hasKey( "autosave" ) )
02851     mAutoSave->setValue( composer.readNumEntry( "autosave" ) );
02852 
02853   if ( general.hasKey( "use-external-editor" )
02854        && general.hasKey( "external-editor" ) ) {
02855     mExternalEditorCheck->setChecked( general.readBoolEntry( "use-external-editor" ) );
02856     mEditorRequester->setURL( general.readPathEntry( "external-editor" ) );
02857   }
02858 }
02859 
02860 void ComposerPage::GeneralTab::save() {
02861   GlobalSettings::self()->setAutoTextSignature(
02862          mAutoAppSignFileCheck->isChecked() ? "auto" : "manual" );
02863   GlobalSettings::self()->setPrependSignature( mTopQuoteCheck->isChecked());
02864   GlobalSettings::self()->setSmartQuote( mSmartQuoteCheck->isChecked() );
02865   GlobalSettings::self()->setQuoteSelectionOnly( mQuoteSelectionOnlyCheck->isChecked() );
02866   GlobalSettings::self()->setStripSignature( mStripSignatureCheck->isChecked() );
02867   GlobalSettings::self()->setRequestMDN( mAutoRequestMDNCheck->isChecked() );
02868   GlobalSettings::self()->setWordWrap( mWordWrapCheck->isChecked() );
02869 
02870   GlobalSettings::self()->setLineWrapWidth( mWrapColumnSpin->value() );
02871   GlobalSettings::self()->setTooManyRecipients( mRecipientCheck->isChecked() );
02872   GlobalSettings::self()->setRecipientThreshold( mRecipientSpin->value() );
02873   GlobalSettings::self()->setAutosaveInterval( mAutoSave->value() );
02874   GlobalSettings::self()->setForwardingInlineByDefault( mForwardTypeCombo->currentItem() == 0 );
02875 
02876   // editor group:
02877   GlobalSettings::self()->setUseExternalEditor( mExternalEditorCheck->isChecked() );
02878   GlobalSettings::self()->setExternalEditor( mEditorRequester->url() );
02879 }
02880 
02881 void ComposerPage::GeneralTab::slotConfigureRecentAddresses( )
02882 {
02883   KRecentAddress::RecentAddressDialog dlg( this );
02884   dlg.setAddresses( RecentAddresses::self( KMKernel::config() )->addresses() );
02885   if ( dlg.exec() ) {
02886     RecentAddresses::self( KMKernel::config() )->clear();
02887     const QStringList &addrList = dlg.addresses();
02888     QStringList::ConstIterator it;
02889     for ( it = addrList.constBegin(); it != addrList.constEnd(); ++it )
02890       RecentAddresses::self( KMKernel::config() )->add( *it );
02891   }
02892 }
02893 
02894 void ComposerPage::GeneralTab::slotConfigureCompletionOrder( )
02895 {
02896   KPIM::LdapSearch search;
02897   KPIM::CompletionOrderEditor editor( &search, this );
02898   editor.exec();
02899 }
02900 
02901 QString ComposerPage::PhrasesTab::helpAnchor() const {
02902   return QString::fromLatin1("configure-composer-phrases");
02903 }
02904 
02905 ComposerPagePhrasesTab::ComposerPagePhrasesTab( QWidget * parent, const char * name )
02906   : ConfigModuleTab( parent, name )
02907 {
02908   // tmp. vars:
02909   QGridLayout *glay;
02910   QPushButton *button;
02911 
02912   glay = new QGridLayout( this, 7, 3, KDialog::spacingHint() );
02913   glay->setMargin( KDialog::marginHint() );
02914   glay->setColStretch( 1, 1 );
02915   glay->setColStretch( 2, 1 );
02916   glay->setRowStretch( 7, 1 );
02917 
02918   // row 0: help text
02919   glay->addMultiCellWidget( new QLabel( i18n("<qt>The following placeholders are "
02920                                              "supported in the reply phrases:<br>"
02921                                              "<b>%D</b>: date, <b>%S</b>: subject,<br>"
02922                                              "<b>%e</b>: sender's address, <b>%F</b>: sender's name, <b>%f</b>: sender's initials,<br>"
02923                                              "<b>%T</b>: recipient's name, <b>%t</b>: recipient's name and address,<br>"
02924                                              "<b>%C</b>: carbon copy names, <b>%c</b>: carbon copy names and addresses,<br>"
02925                                              "<b>%%</b>: percent sign, <b>%_</b>: space, "
02926                                              "<b>%L</b>: linebreak</qt>"), this ),
02927                             0, 0, 0, 2 ); // row 0; cols 0..2
02928 
02929   // row 1: label and language combo box:
02930   mPhraseLanguageCombo = new LanguageComboBox( false, this );
02931   glay->addWidget( new QLabel( mPhraseLanguageCombo,
02932                                i18n("Lang&uage:"), this ), 1, 0 );
02933   glay->addMultiCellWidget( mPhraseLanguageCombo, 1, 1, 1, 2 );
02934   connect( mPhraseLanguageCombo, SIGNAL(activated(const QString&)),
02935            this, SLOT(slotLanguageChanged(const QString&)) );
02936 
02937   // row 2: "add..." and "remove" push buttons:
02938   button = new QPushButton( i18n("A&dd..."), this );
02939   button->setAutoDefault( false );
02940   glay->addWidget( button, 2, 1 );
02941   mRemoveButton = new QPushButton( i18n("Re&move"), this );
02942   mRemoveButton->setAutoDefault( false );
02943   mRemoveButton->setEnabled( false ); // combo doesn't contain anything...
02944   glay->addWidget( mRemoveButton, 2, 2 );
02945   connect( button, SIGNAL(clicked()),
02946            this, SLOT(slotNewLanguage()) );
02947   connect( mRemoveButton, SIGNAL(clicked()),
02948            this, SLOT(slotRemoveLanguage()) );
02949 
02950   // row 3: "reply to sender" line edit and label:
02951   mPhraseReplyEdit = new KLineEdit( this );
02952   connect( mPhraseReplyEdit, SIGNAL( textChanged( const QString& ) ),
02953            this, SLOT( slotEmitChanged( void ) ) );
02954   glay->addWidget( new QLabel( mPhraseReplyEdit,
02955                                i18n("Reply to se&nder:"), this ), 3, 0 );
02956   glay->addMultiCellWidget( mPhraseReplyEdit, 3, 3, 1, 2 ); // cols 1..2
02957 
02958   // row 4: "reply to all" line edit and label:
02959   mPhraseReplyAllEdit = new KLineEdit( this );
02960   connect( mPhraseReplyAllEdit, SIGNAL( textChanged( const QString& ) ),
02961            this, SLOT( slotEmitChanged( void ) ) );
02962   glay->addWidget( new QLabel( mPhraseReplyAllEdit,
02963                                i18n("Repl&y to all:"), this ), 4, 0 );
02964   glay->addMultiCellWidget( mPhraseReplyAllEdit, 4, 4, 1, 2 ); // cols 1..2
02965 
02966   // row 5: "forward" line edit and label:
02967   mPhraseForwardEdit = new KLineEdit( this );
02968   connect( mPhraseForwardEdit, SIGNAL( textChanged( const QString& ) ),
02969            this, SLOT( slotEmitChanged( void ) ) );
02970   glay->addWidget( new QLabel( mPhraseForwardEdit,
02971                                i18n("&Forward:"), this ), 5, 0 );
02972   glay->addMultiCellWidget( mPhraseForwardEdit, 5, 5, 1, 2 ); // cols 1..2
02973 
02974   // row 6: "quote indicator" line edit and label:
02975   mPhraseIndentPrefixEdit = new KLineEdit( this );
02976   connect( mPhraseIndentPrefixEdit, SIGNAL( textChanged( const QString& ) ),
02977            this, SLOT( slotEmitChanged( void ) ) );
02978   glay->addWidget( new QLabel( mPhraseIndentPrefixEdit,
02979                                i18n("&Quote indicator:"), this ), 6, 0 );
02980   glay->addMultiCellWidget( mPhraseIndentPrefixEdit, 6, 6, 1, 2 );
02981 
02982   // row 7: spacer
02983 }
02984 
02985 
02986 void ComposerPage::PhrasesTab::setLanguageItemInformation( int index ) {
02987   assert( 0 <= index && index < (int)mLanguageList.count() );
02988 
02989   LanguageItem &l = *mLanguageList.at( index );
02990 
02991   mPhraseReplyEdit->setText( l.mReply );
02992   mPhraseReplyAllEdit->setText( l.mReplyAll );
02993   mPhraseForwardEdit->setText( l.mForward );
02994   mPhraseIndentPrefixEdit->setText( l.mIndentPrefix );
02995 }
02996 
02997 void ComposerPage::PhrasesTab::saveActiveLanguageItem() {
02998   int index = mActiveLanguageItem;
02999   if (index == -1) return;
03000   assert( 0 <= index && index < (int)mLanguageList.count() );
03001 
03002   LanguageItem &l = *mLanguageList.at( index );
03003 
03004   l.mReply = mPhraseReplyEdit->text();
03005   l.mReplyAll = mPhraseReplyAllEdit->text();
03006   l.mForward = mPhraseForwardEdit->text();
03007   l.mIndentPrefix = mPhraseIndentPrefixEdit->text();
03008 }
03009 
03010 void ComposerPage::PhrasesTab::slotNewLanguage()
03011 {
03012   NewLanguageDialog dialog( mLanguageList, parentWidget(), "New", true );
03013   if ( dialog.exec() == QDialog::Accepted ) slotAddNewLanguage( dialog.language() );
03014 }
03015 
03016 void ComposerPage::PhrasesTab::slotAddNewLanguage( const QString& lang )
03017 {
03018   mPhraseLanguageCombo->setCurrentItem(
03019     mPhraseLanguageCombo->insertLanguage( lang ) );
03020   KLocale locale("kmail");
03021   locale.setLanguage( lang );
03022   mLanguageList.append(
03023      LanguageItem( lang,
03024                    locale.translate("On %D, you wrote:"),
03025                    locale.translate("On %D, %F wrote:"),
03026                    locale.translate("Forwarded Message"),
03027                    locale.translate(">%_") ) );
03028   mRemoveButton->setEnabled( true );
03029   slotLanguageChanged( QString::null );
03030 }
03031 
03032 void ComposerPage::PhrasesTab::slotRemoveLanguage()
03033 {
03034   assert( mPhraseLanguageCombo->count() > 1 );
03035   int index = mPhraseLanguageCombo->currentItem();
03036   assert( 0 <= index && index < (int)mLanguageList.count() );
03037 
03038   // remove current item from internal list and combobox:
03039   mLanguageList.remove( mLanguageList.at( index ) );
03040   mPhraseLanguageCombo->removeItem( index );
03041 
03042   if ( index >= (int)mLanguageList.count() ) index--;
03043 
03044   mActiveLanguageItem = index;
03045   setLanguageItemInformation( index );
03046   mRemoveButton->setEnabled( mLanguageList.count() > 1 );
03047   emit changed( true );
03048 }
03049 
03050 void ComposerPage::PhrasesTab::slotLanguageChanged( const QString& )
03051 {
03052   int index = mPhraseLanguageCombo->currentItem();
03053   assert( index < (int)mLanguageList.count() );
03054   saveActiveLanguageItem();
03055   mActiveLanguageItem = index;
03056   setLanguageItemInformation( index );
03057   emit changed( true );
03058 }
03059 
03060 
03061 void ComposerPage::PhrasesTab::doLoadFromGlobalSettings() {
03062   mLanguageList.clear();
03063   mPhraseLanguageCombo->clear();
03064   mActiveLanguageItem = -1;
03065 
03066   int numLang = GlobalSettings::self()->replyLanguagesCount();
03067   int currentNr = GlobalSettings::self()->replyCurrentLanguage();
03068 
03069   // build mLanguageList and mPhraseLanguageCombo:
03070   for ( int i = 0 ; i < numLang ; i++ ) {
03071     ReplyPhrases replyPhrases( QString::number(i) );
03072     replyPhrases.readConfig();
03073     QString lang = replyPhrases.language();
03074     mLanguageList.append(
03075          LanguageItem( lang,
03076                        replyPhrases.phraseReplySender(),
03077                        replyPhrases.phraseReplyAll(),
03078                        replyPhrases.phraseForward(),
03079                        replyPhrases.indentPrefix() ) );
03080     mPhraseLanguageCombo->insertLanguage( lang );
03081   }
03082 
03083   if ( currentNr >= numLang || currentNr < 0 )
03084     currentNr = 0;
03085 
03086   if ( numLang == 0 ) {
03087     slotAddNewLanguage( KGlobal::locale()->language() );
03088   }
03089 
03090   mPhraseLanguageCombo->setCurrentItem( currentNr );
03091   mActiveLanguageItem = currentNr;
03092   setLanguageItemInformation( currentNr );
03093   mRemoveButton->setEnabled( mLanguageList.count() > 1 );
03094 }
03095 
03096 void ComposerPage::PhrasesTab::save() {
03097   GlobalSettings::self()->setReplyLanguagesCount( mLanguageList.count() );
03098   GlobalSettings::self()->setReplyCurrentLanguage( mPhraseLanguageCombo->currentItem() );
03099 
03100   saveActiveLanguageItem();
03101   LanguageItemList::Iterator it = mLanguageList.begin();
03102   for ( int i = 0 ; it != mLanguageList.end() ; ++it, ++i ) {
03103     ReplyPhrases replyPhrases( QString::number(i) );
03104     replyPhrases.setLanguage( (*it).mLanguage );
03105     replyPhrases.setPhraseReplySender( (*it).mReply );
03106     replyPhrases.setPhraseReplyAll( (*it).mReplyAll );
03107     replyPhrases.setPhraseForward( (*it).mForward );
03108     replyPhrases.setIndentPrefix( (*it).mIndentPrefix );
03109     replyPhrases.writeConfig();
03110   }
03111 }
03112 
03113 QString ComposerPage::TemplatesTab::helpAnchor() const {
03114   return QString::fromLatin1("configure-composer-templates");
03115 }
03116 
03117 ComposerPageTemplatesTab::ComposerPageTemplatesTab( QWidget * parent, const char * name )
03118   : ConfigModuleTab ( parent, name )
03119 {
03120   QVBoxLayout* vlay = new QVBoxLayout( this, 0, KDialog::spacingHint() );
03121 
03122   mWidget = new TemplatesConfiguration( this );
03123   vlay->addWidget( mWidget );
03124 
03125   connect( mWidget, SIGNAL( changed() ),
03126            this, SLOT( slotEmitChanged( void ) ) );
03127 }
03128 
03129 void ComposerPage::TemplatesTab::doLoadFromGlobalSettings() {
03130     mWidget->loadFromGlobal();
03131 }
03132 
03133 void ComposerPage::TemplatesTab::save() {
03134     mWidget->saveToGlobal();
03135 }
03136 
03137 QString ComposerPage::CustomTemplatesTab::helpAnchor() const {
03138   return QString::fromLatin1("configure-composer-custom-templates");
03139 }
03140 
03141 ComposerPageCustomTemplatesTab::ComposerPageCustomTemplatesTab( QWidget * parent, const char * name )
03142   : ConfigModuleTab ( parent, name )
03143 {
03144   QVBoxLayout* vlay = new QVBoxLayout( this, 0, KDialog::spacingHint() );
03145 
03146   mWidget = new CustomTemplates( this );
03147   vlay->addWidget( mWidget );
03148 
03149   connect( mWidget, SIGNAL( changed() ),
03150            this, SLOT( slotEmitChanged( void ) ) );
03151 }
03152 
03153 void ComposerPage::CustomTemplatesTab::doLoadFromGlobalSettings() {
03154     mWidget->load();
03155 }
03156 
03157 void ComposerPage::CustomTemplatesTab::save() {
03158     mWidget->save();
03159 }
03160 
03161 QString ComposerPage::SubjectTab::helpAnchor() const {
03162   return QString::fromLatin1("configure-composer-subject");
03163 }
03164 
03165 ComposerPageSubjectTab::ComposerPageSubjectTab( QWidget * parent, const char * name )
03166   : ConfigModuleTab( parent, name )
03167 {
03168   // tmp. vars:
03169   QVBoxLayout *vlay;
03170   QGroupBox   *group;
03171   QLabel      *label;
03172 
03173 
03174   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03175 
03176   group = new QVGroupBox( i18n("Repl&y Subject Prefixes"), this );
03177   group->layout()->setSpacing( KDialog::spacingHint() );
03178 
03179   // row 0: help text:
03180   label = new QLabel( i18n("Recognize any sequence of the following prefixes\n"
03181                            "(entries are case-insensitive regular expressions):"), group );
03182   label->setAlignment( AlignLeft|WordBreak );
03183 
03184   // row 1, string list editor:
03185   SimpleStringListEditor::ButtonCode buttonCode =
03186     static_cast<SimpleStringListEditor::ButtonCode>( SimpleStringListEditor::Add | SimpleStringListEditor::Remove | SimpleStringListEditor::Modify );
03187   mReplyListEditor =
03188     new SimpleStringListEditor( group, 0, buttonCode,
03189                                 i18n("A&dd..."), i18n("Re&move"),
03190                                 i18n("Mod&ify..."),
03191                                 i18n("Enter new reply prefix:") );
03192   connect( mReplyListEditor, SIGNAL( changed( void ) ),
03193            this, SLOT( slotEmitChanged( void ) ) );
03194 
03195   // row 2: "replace [...]" check box:
03196   mReplaceReplyPrefixCheck = new QCheckBox(
03197      GlobalSettings::self()->replaceReplyPrefixItem()->label(),
03198      group, "kcfg_ReplaceReplyPrefix" );
03199   connect( mReplaceReplyPrefixCheck, SIGNAL( stateChanged( int ) ),
03200            this, SLOT( slotEmitChanged( void ) ) );
03201 
03202   vlay->addWidget( group );
03203 
03204 
03205   group = new QVGroupBox( i18n("For&ward Subject Prefixes"), this );
03206   group->layout()->setSpacing( KDialog::marginHint() );
03207 
03208   // row 0: help text:
03209   label= new QLabel( i18n("Recognize any sequence of the following prefixes\n"
03210                           "(entries are case-insensitive regular expressions):"), group );
03211   label->setAlignment( AlignLeft|WordBreak );
03212 
03213   // row 1: string list editor
03214   mForwardListEditor =
03215     new SimpleStringListEditor( group, 0, buttonCode,
03216                                 i18n("Add..."),
03217                                 i18n("Remo&ve"),
03218                                 i18n("Modify..."),
03219                                 i18n("Enter new forward prefix:") );
03220   connect( mForwardListEditor, SIGNAL( changed( void ) ),
03221            this, SLOT( slotEmitChanged( void ) ) );
03222 
03223   // row 3: "replace [...]" check box:
03224   mReplaceForwardPrefixCheck = new QCheckBox(
03225        GlobalSettings::self()->replaceForwardPrefixItem()->label(),
03226        group, "kcfg_ReplaceForwardPrefix" );
03227   connect( mReplaceForwardPrefixCheck, SIGNAL( stateChanged( int ) ),
03228            this, SLOT( slotEmitChanged( void ) ) );
03229 
03230   vlay->addWidget( group );
03231 }
03232 
03233 void ComposerPage::SubjectTab::doLoadFromGlobalSettings() {
03234   mReplyListEditor->setStringList( GlobalSettings::self()->replyPrefixes() );
03235   mReplaceReplyPrefixCheck->setChecked( GlobalSettings::self()->replaceReplyPrefix() );
03236   mForwardListEditor->setStringList( GlobalSettings::self()->forwardPrefixes() );
03237   mReplaceForwardPrefixCheck->setChecked( GlobalSettings::self()->replaceForwardPrefix() );
03238 }
03239 
03240 void ComposerPage::SubjectTab::save() {
03241   GlobalSettings::self()->setReplyPrefixes( mReplyListEditor->stringList() );
03242   GlobalSettings::self()->setForwardPrefixes( mForwardListEditor->stringList() );
03243 }
03244 
03245 QString ComposerPage::CharsetTab::helpAnchor() const {
03246   return QString::fromLatin1("configure-composer-charset");
03247 }
03248 
03249 ComposerPageCharsetTab::ComposerPageCharsetTab( QWidget * parent, const char * name )
03250   : ConfigModuleTab( parent, name )
03251 {
03252   // tmp. vars:
03253   QVBoxLayout *vlay;
03254   QLabel      *label;
03255 
03256   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03257 
03258   label = new QLabel( i18n("This list is checked for every outgoing message "
03259                            "from the top to the bottom for a charset that "
03260                            "contains all required characters."), this );
03261   label->setAlignment( WordBreak);
03262   vlay->addWidget( label );
03263 
03264   mCharsetListEditor =
03265     new SimpleStringListEditor( this, 0, SimpleStringListEditor::All,
03266                                 i18n("A&dd..."), i18n("Remo&ve"),
03267                                 i18n("&Modify..."), i18n("Enter charset:") );
03268   connect( mCharsetListEditor, SIGNAL( changed( void ) ),
03269            this, SLOT( slotEmitChanged( void ) ) );
03270 
03271   vlay->addWidget( mCharsetListEditor, 1 );
03272 
03273   mKeepReplyCharsetCheck = new QCheckBox( i18n("&Keep original charset when "
03274                                                 "replying or forwarding (if "
03275                                                 "possible)"), this );
03276   connect( mKeepReplyCharsetCheck, SIGNAL ( stateChanged( int ) ),
03277            this, SLOT( slotEmitChanged( void ) ) );
03278   vlay->addWidget( mKeepReplyCharsetCheck );
03279 
03280   connect( mCharsetListEditor, SIGNAL(aboutToAdd(QString&)),
03281            this, SLOT(slotVerifyCharset(QString&)) );
03282 }
03283 
03284 void ComposerPage::CharsetTab::slotVerifyCharset( QString & charset ) {
03285   if ( charset.isEmpty() ) return;
03286 
03287   // KCharsets::codecForName("us-ascii") returns "iso-8859-1" (cf. Bug #49812)
03288   // therefore we have to treat this case specially
03289   if ( charset.lower() == QString::fromLatin1("us-ascii") ) {
03290     charset = QString::fromLatin1("us-ascii");
03291     return;
03292   }
03293 
03294   if ( charset.lower() == QString::fromLatin1("locale") ) {
03295     charset =  QString::fromLatin1("%1 (locale)")
03296       .arg( QCString( kmkernel->networkCodec()->mimeName() ).lower() );
03297     return;
03298   }
03299 
03300   bool ok = false;
03301   QTextCodec *codec = KGlobal::charsets()->codecForName( charset, ok );
03302   if ( ok && codec ) {
03303     charset = QString::fromLatin1( codec->mimeName() ).lower();
03304     return;
03305   }
03306 
03307   KMessageBox::sorry( this, i18n("This charset is not supported.") );
03308   charset = QString::null;
03309 }
03310 
03311 void ComposerPage::CharsetTab::doLoadOther() {
03312   KConfigGroup composer( KMKernel::config(), "Composer" );
03313 
03314   QStringList charsets = composer.readListEntry( "pref-charsets" );
03315   for ( QStringList::Iterator it = charsets.begin() ;
03316         it != charsets.end() ; ++it )
03317     if ( (*it) == QString::fromLatin1("locale") ) {
03318       QCString cset = kmkernel->networkCodec()->mimeName();
03319       KPIM::kAsciiToLower( cset.data() );
03320       (*it) = QString("%1 (locale)").arg( cset );
03321     }
03322 
03323   mCharsetListEditor->setStringList( charsets );
03324   mKeepReplyCharsetCheck->setChecked( !composer.readBoolEntry( "force-reply-charset", false ) );
03325 }
03326 
03327 void ComposerPage::CharsetTab::save() {
03328   KConfigGroup composer( KMKernel::config(), "Composer" );
03329 
03330   QStringList charsetList = mCharsetListEditor->stringList();
03331   QStringList::Iterator it = charsetList.begin();
03332   for ( ; it != charsetList.end() ; ++it )
03333     if ( (*it).endsWith("(locale)") )
03334       (*it) = "locale";
03335   composer.writeEntry( "pref-charsets", charsetList );
03336   composer.writeEntry( "force-reply-charset",
03337                        !mKeepReplyCharsetCheck->isChecked() );
03338 }
03339 
03340 QString ComposerPage::HeadersTab::helpAnchor() const {
03341   return QString::fromLatin1("configure-composer-headers");
03342 }
03343 
03344 ComposerPageHeadersTab::ComposerPageHeadersTab( QWidget * parent, const char * name )
03345   : ConfigModuleTab( parent, name )
03346 {
03347   // tmp. vars:
03348   QVBoxLayout *vlay;
03349   QHBoxLayout *hlay;
03350   QGridLayout *glay;
03351   QLabel      *label;
03352   QPushButton *button;
03353 
03354   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03355 
03356   // "Use custom Message-Id suffix" checkbox:
03357   mCreateOwnMessageIdCheck =
03358     new QCheckBox( i18n("&Use custom message-id suffix"), this );
03359   connect( mCreateOwnMessageIdCheck, SIGNAL ( stateChanged( int ) ),
03360            this, SLOT( slotEmitChanged( void ) ) );
03361   vlay->addWidget( mCreateOwnMessageIdCheck );
03362 
03363   // "Message-Id suffix" line edit and label:
03364   hlay = new QHBoxLayout( vlay ); // inherits spacing
03365   mMessageIdSuffixEdit = new KLineEdit( this );
03366   // only ASCII letters, digits, plus, minus and dots are allowed
03367   mMessageIdSuffixValidator =
03368     new QRegExpValidator( QRegExp( "[a-zA-Z0-9+-]+(?:\\.[a-zA-Z0-9+-]+)*" ), this );
03369   mMessageIdSuffixEdit->setValidator( mMessageIdSuffixValidator );
03370   label = new QLabel( mMessageIdSuffixEdit,
03371                       i18n("Custom message-&id suffix:"), this );
03372   label->setEnabled( false ); // since !mCreateOwnMessageIdCheck->isChecked()
03373   mMessageIdSuffixEdit->setEnabled( false );
03374   hlay->addWidget( label );
03375   hlay->addWidget( mMessageIdSuffixEdit, 1 );
03376   connect( mCreateOwnMessageIdCheck, SIGNAL(toggled(bool) ),
03377            label, SLOT(setEnabled(bool)) );
03378   connect( mCreateOwnMessageIdCheck, SIGNAL(toggled(bool) ),
03379            mMessageIdSuffixEdit, SLOT(setEnabled(bool)) );
03380   connect( mMessageIdSuffixEdit, SIGNAL( textChanged( const QString& ) ),
03381            this, SLOT( slotEmitChanged( void ) ) );
03382 
03383   // horizontal rule and "custom header fields" label:
03384   vlay->addWidget( new KSeparator( KSeparator::HLine, this ) );
03385   vlay->addWidget( new QLabel( i18n("Define custom mime header fields:"), this) );
03386 
03387   // "custom header fields" listbox:
03388   glay = new QGridLayout( vlay, 5, 3 ); // inherits spacing
03389   glay->setRowStretch( 2, 1 );
03390   glay->setColStretch( 1, 1 );
03391   mTagList = new ListView( this, "tagList" );
03392   mTagList->addColumn( i18n("Name") );
03393   mTagList->addColumn( i18n("Value") );
03394   mTagList->setAllColumnsShowFocus( true );
03395   mTagList->setSorting( -1 );
03396   connect( mTagList, SIGNAL(selectionChanged()),
03397            this, SLOT(slotMimeHeaderSelectionChanged()) );
03398   glay->addMultiCellWidget( mTagList, 0, 2, 0, 1 );
03399 
03400   // "new" and "remove" buttons:
03401   button = new QPushButton( i18n("Ne&w"), this );
03402   connect( button, SIGNAL(clicked()), this, SLOT(slotNewMimeHeader()) );
03403   button->setAutoDefault( false );
03404   glay->addWidget( button, 0, 2 );
03405   mRemoveHeaderButton = new QPushButton( i18n("Re&move"), this );
03406   connect( mRemoveHeaderButton, SIGNAL(clicked()),
03407            this, SLOT(slotRemoveMimeHeader()) );
03408   button->setAutoDefault( false );
03409   glay->addWidget( mRemoveHeaderButton, 1, 2 );
03410 
03411   // "name" and "value" line edits and labels:
03412   mTagNameEdit = new KLineEdit( this );
03413   mTagNameEdit->setEnabled( false );
03414   mTagNameLabel = new QLabel( mTagNameEdit, i18n("&Name:"), this );
03415   mTagNameLabel->setEnabled( false );
03416   glay->addWidget( mTagNameLabel, 3, 0 );
03417   glay->addWidget( mTagNameEdit, 3, 1 );
03418   connect( mTagNameEdit, SIGNAL(textChanged(const QString&)),
03419            this, SLOT(slotMimeHeaderNameChanged(const QString&)) );
03420 
03421   mTagValueEdit = new KLineEdit( this );
03422   mTagValueEdit->setEnabled( false );
03423   mTagValueLabel = new QLabel( mTagValueEdit, i18n("&Value:"), this );
03424   mTagValueLabel->setEnabled( false );
03425   glay->addWidget( mTagValueLabel, 4, 0 );
03426   glay->addWidget( mTagValueEdit, 4, 1 );
03427   connect( mTagValueEdit, SIGNAL(textChanged(const QString&)),
03428            this, SLOT(slotMimeHeaderValueChanged(const QString&)) );
03429 }
03430 
03431 void ComposerPage::HeadersTab::slotMimeHeaderSelectionChanged()
03432 {
03433   QListViewItem * item = mTagList->selectedItem();
03434 
03435   if ( item ) {
03436     mTagNameEdit->setText( item->text( 0 ) );
03437     mTagValueEdit->setText( item->text( 1 ) );
03438   } else {
03439     mTagNameEdit->clear();
03440     mTagValueEdit->clear();
03441   }
03442   mRemoveHeaderButton->setEnabled( item );
03443   mTagNameEdit->setEnabled( item );
03444   mTagValueEdit->setEnabled( item );
03445   mTagNameLabel->setEnabled( item );
03446   mTagValueLabel->setEnabled( item );
03447 }
03448 
03449 
03450 void ComposerPage::HeadersTab::slotMimeHeaderNameChanged( const QString & text ) {
03451   // is called on ::setup(), when clearing the line edits. So be
03452   // prepared to not find a selection:
03453   QListViewItem * item = mTagList->selectedItem();
03454   if ( item )
03455     item->setText( 0, text );
03456   emit changed( true );
03457 }
03458 
03459 
03460 void ComposerPage::HeadersTab::slotMimeHeaderValueChanged( const QString & text ) {
03461   // is called on ::setup(), when clearing the line edits. So be
03462   // prepared to not find a selection:
03463   QListViewItem * item = mTagList->selectedItem();
03464   if ( item )
03465     item->setText( 1, text );
03466   emit changed( true );
03467 }
03468 
03469 
03470 void ComposerPage::HeadersTab::slotNewMimeHeader()
03471 {
03472   QListViewItem *listItem = new QListViewItem( mTagList );
03473   mTagList->setCurrentItem( listItem );
03474   mTagList->setSelected( listItem, true );
03475   emit changed( true );
03476 }
03477 
03478 
03479 void ComposerPage::HeadersTab::slotRemoveMimeHeader()
03480 {
03481   // calling this w/o selection is a programming error:
03482   QListViewItem * item = mTagList->selectedItem();
03483   if ( !item ) {
03484     kdDebug(5006) << "==================================================\n"
03485                   << "Error: Remove button was pressed although no custom header was selected\n"
03486                   << "==================================================\n";
03487     return;
03488   }
03489 
03490   QListViewItem * below = item->nextSibling();
03491   delete item;
03492 
03493   if ( below )
03494     mTagList->setSelected( below, true );
03495   else if ( mTagList->lastItem() )
03496     mTagList->setSelected( mTagList->lastItem(), true );
03497   emit changed( true );
03498 }
03499 
03500 void ComposerPage::HeadersTab::doLoadOther() {
03501   KConfigGroup general( KMKernel::config(), "General" );
03502 
03503   QString suffix = general.readEntry( "myMessageIdSuffix" );
03504   mMessageIdSuffixEdit->setText( suffix );
03505   bool state = ( !suffix.isEmpty() &&
03506             general.readBoolEntry( "useCustomMessageIdSuffix", false ) );
03507   mCreateOwnMessageIdCheck->setChecked( state );
03508 
03509   mTagList->clear();
03510   mTagNameEdit->clear();
03511   mTagValueEdit->clear();
03512 
03513   QListViewItem * item = 0;
03514 
03515   int count = general.readNumEntry( "mime-header-count", 0 );
03516   for( int i = 0 ; i < count ; i++ ) {
03517     KConfigGroup config( KMKernel::config(),
03518                          QCString("Mime #") + QCString().setNum(i) );
03519     QString name  = config.readEntry( "name" );
03520     QString value = config.readEntry( "value" );
03521     if( !name.isEmpty() )
03522       item = new QListViewItem( mTagList, item, name, value );
03523   }
03524   if ( mTagList->childCount() ) {
03525     mTagList->setCurrentItem( mTagList->firstChild() );
03526     mTagList->setSelected( mTagList->firstChild(), true );
03527   }
03528   else {
03529     // disable the "Remove" button
03530     mRemoveHeaderButton->setEnabled( false );
03531   }
03532 }
03533 
03534 void ComposerPage::HeadersTab::save() {
03535   KConfigGroup general( KMKernel::config(), "General" );
03536 
03537   general.writeEntry( "useCustomMessageIdSuffix",
03538                       mCreateOwnMessageIdCheck->isChecked() );
03539   general.writeEntry( "myMessageIdSuffix",
03540                       mMessageIdSuffixEdit->text() );
03541 
03542   int numValidEntries = 0;
03543   QListViewItem * item = mTagList->firstChild();
03544   for ( ; item ; item = item->itemBelow() )
03545     if( !item->text(0).isEmpty() ) {
03546       KConfigGroup config( KMKernel::config(), QCString("Mime #")
03547                              + QCString().setNum( numValidEntries ) );
03548       config.writeEntry( "name",  item->text( 0 ) );
03549       config.writeEntry( "value", item->text( 1 ) );
03550       numValidEntries++;
03551     }
03552   general.writeEntry( "mime-header-count", numValidEntries );
03553 }
03554 
03555 QString ComposerPage::AttachmentsTab::helpAnchor() const {
03556   return QString::fromLatin1("configure-composer-attachments");
03557 }
03558 
03559 ComposerPageAttachmentsTab::ComposerPageAttachmentsTab( QWidget * parent,
03560                                                         const char * name )
03561   : ConfigModuleTab( parent, name ) {
03562   // tmp. vars:
03563   QVBoxLayout *vlay;
03564   QLabel      *label;
03565 
03566   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03567 
03568   // "Outlook compatible attachment naming" check box
03569   mOutlookCompatibleCheck =
03570     new QCheckBox( i18n( "Outlook-compatible attachment naming" ), this );
03571   mOutlookCompatibleCheck->setChecked( false );
03572   QToolTip::add( mOutlookCompatibleCheck, i18n(
03573     "Turn this option on to make Outlook(tm) understand attachment names "
03574     "containing non-English characters" ) );
03575   connect( mOutlookCompatibleCheck, SIGNAL( stateChanged( int ) ),
03576            this, SLOT( slotEmitChanged( void ) ) );
03577   connect( mOutlookCompatibleCheck, SIGNAL( clicked() ),
03578            this, SLOT( slotOutlookCompatibleClicked() ) );
03579   vlay->addWidget( mOutlookCompatibleCheck );
03580   vlay->addSpacing( 5 );
03581 
03582   // "Enable detection of missing attachments" check box
03583   mMissingAttachmentDetectionCheck =
03584     new QCheckBox( i18n("E&nable detection of missing attachments"), this );
03585   mMissingAttachmentDetectionCheck->setChecked( true );
03586   connect( mMissingAttachmentDetectionCheck, SIGNAL( stateChanged( int ) ),
03587            this, SLOT( slotEmitChanged( void ) ) );
03588   vlay->addWidget( mMissingAttachmentDetectionCheck );
03589 
03590   // "Attachment key words" label and string list editor
03591   label = new QLabel( i18n("Recognize any of the following key words as "
03592                            "intention to attach a file:"), this );
03593   label->setAlignment( AlignLeft|WordBreak );
03594   vlay->addWidget( label );
03595 
03596   SimpleStringListEditor::ButtonCode buttonCode =
03597     static_cast<SimpleStringListEditor::ButtonCode>( SimpleStringListEditor::Add | SimpleStringListEditor::Remove | SimpleStringListEditor::Modify );
03598   mAttachWordsListEditor =
03599     new SimpleStringListEditor( this, 0, buttonCode,
03600                                 i18n("A&dd..."), i18n("Re&move"),
03601                                 i18n("Mod&ify..."),
03602                                 i18n("Enter new key word:") );
03603   connect( mAttachWordsListEditor, SIGNAL( changed( void ) ),
03604            this, SLOT( slotEmitChanged( void ) ) );
03605   vlay->addWidget( mAttachWordsListEditor );
03606 
03607   connect( mMissingAttachmentDetectionCheck, SIGNAL(toggled(bool) ),
03608            label, SLOT(setEnabled(bool)) );
03609   connect( mMissingAttachmentDetectionCheck, SIGNAL(toggled(bool) ),
03610            mAttachWordsListEditor, SLOT(setEnabled(bool)) );
03611 }
03612 
03613 void ComposerPage::AttachmentsTab::doLoadFromGlobalSettings() {
03614   mOutlookCompatibleCheck->setChecked(
03615     GlobalSettings::self()->outlookCompatibleAttachments() );
03616   mMissingAttachmentDetectionCheck->setChecked(
03617     GlobalSettings::self()->showForgottenAttachmentWarning() );
03618   QStringList attachWordsList = GlobalSettings::self()->attachmentKeywords();
03619   if ( attachWordsList.isEmpty() ) {
03620     // default value
03621     attachWordsList << QString::fromLatin1("attachment")
03622                     << QString::fromLatin1("attached");
03623     if ( QString::fromLatin1("attachment") != i18n("attachment") )
03624       attachWordsList << i18n("attachment");
03625     if ( QString::fromLatin1("attached") != i18n("attached") )
03626       attachWordsList << i18n("attached");
03627   }
03628 
03629   mAttachWordsListEditor->setStringList( attachWordsList );
03630 }
03631 
03632 void ComposerPage::AttachmentsTab::save() {
03633   GlobalSettings::self()->setOutlookCompatibleAttachments(
03634     mOutlookCompatibleCheck->isChecked() );
03635   GlobalSettings::self()->setShowForgottenAttachmentWarning(
03636     mMissingAttachmentDetectionCheck->isChecked() );
03637   GlobalSettings::self()->setAttachmentKeywords(
03638     mAttachWordsListEditor->stringList() );
03639 }
03640 
03641 void ComposerPageAttachmentsTab::slotOutlookCompatibleClicked()
03642 {
03643   if (mOutlookCompatibleCheck->isChecked()) {
03644     KMessageBox::information(0,i18n("You have chosen to "
03645     "encode attachment names containing non-English characters in a way that "
03646     "is understood by Outlook(tm) and other mail clients that do not "
03647     "support standard-compliant encoded attachment names.\n"
03648     "Note that KMail may create non-standard compliant messages, "
03649     "and consequently it is possible that your messages will not be "
03650     "understood by standard-compliant mail clients; so, unless you have no "
03651     "other choice, you should not enable this option." ) );
03652   }
03653 }
03654 
03655 // *************************************************************
03656 // *                                                           *
03657 // *                      SecurityPage                         *
03658 // *                                                           *
03659 // *************************************************************
03660 QString SecurityPage::helpAnchor() const {
03661   return QString::fromLatin1("configure-security");
03662 }
03663 
03664 SecurityPage::SecurityPage( QWidget * parent, const char * name )
03665   : ConfigModuleWithTabs( parent, name )
03666 {
03667   //
03668   // "Reading" tab:
03669   //
03670   mGeneralTab = new GeneralTab(); //  @TODO: rename
03671   addTab( mGeneralTab, i18n("&Reading") );
03672 
03673   //
03674   // "Composing" tab:
03675   //
03676   mComposerCryptoTab = new ComposerCryptoTab();
03677   addTab( mComposerCryptoTab, i18n("Composing") );
03678 
03679   //
03680   // "Warnings" tab:
03681   //
03682   mWarningTab = new WarningTab();
03683   addTab( mWarningTab, i18n("Warnings") );
03684 
03685   //
03686   // "S/MIME Validation" tab:
03687   //
03688   mSMimeTab = new SMimeTab();
03689   addTab( mSMimeTab, i18n("S/MIME &Validation") );
03690 
03691   //
03692   // "Crypto Backends" tab:
03693   //
03694   mCryptPlugTab = new CryptPlugTab();
03695   addTab( mCryptPlugTab, i18n("Crypto Backe&nds") );
03696   load();
03697 }
03698 
03699 
03700 void SecurityPage::installProfile( KConfig * profile ) {
03701   mGeneralTab->installProfile( profile );
03702   mComposerCryptoTab->installProfile( profile );
03703   mWarningTab->installProfile( profile );
03704   mSMimeTab->installProfile( profile );
03705 }
03706 
03707 QString SecurityPage::GeneralTab::helpAnchor() const {
03708   return QString::fromLatin1("configure-security-reading");
03709 }
03710 
03711 SecurityPageGeneralTab::SecurityPageGeneralTab( QWidget * parent, const char * name )
03712   : ConfigModuleTab ( parent, name )
03713 {
03714   // tmp. vars:
03715   QVBoxLayout  *vlay;
03716   QHBox        *hbox;
03717   QGroupBox    *group;
03718   QRadioButton *radio;
03719   KActiveLabel *label;
03720   QWidget      *w;
03721   QString       msg;
03722 
03723   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03724 
03725   // QWhat'sThis texts
03726   QString htmlWhatsThis = i18n( "<qt><p>Messages sometimes come in both formats. "
03727               "This option controls whether you want the HTML part or the plain "
03728               "text part to be displayed.</p>"
03729               "<p>Displaying the HTML part makes the message look better, "
03730               "but at the same time increases the risk of security holes "
03731               "being exploited.</p>"
03732               "<p>Displaying the plain text part loses much of the message's "
03733               "formatting, but makes it almost <em>impossible</em> "
03734               "to exploit security holes in the HTML renderer (Konqueror).</p>"
03735               "<p>The option below guards against one common misuse of HTML "
03736               "messages, but it cannot guard against security issues that were "
03737               "not known at the time this version of KMail was written.</p>"
03738               "<p>It is therefore advisable to <em>not</em> prefer HTML to "
03739               "plain text.</p>"
03740               "<p><b>Note:</b> You can set this option on a per-folder basis "
03741               "from the <i>Folder</i> menu of KMail's main window.</p></qt>" );
03742 
03743   QString externalWhatsThis = i18n( "<qt><p>Some mail advertisements are in HTML "
03744               "and contain references to, for example, images that the advertisers"
03745               " employ to find out that you have read their message "
03746               "(&quot;web bugs&quot;).</p>"
03747               "<p>There is no valid reason to load images off the Internet like "
03748               "this, since the sender can always attach the required images "
03749               "directly to the message.</p>"
03750               "<p>To guard from such a misuse of the HTML displaying feature "
03751               "of KMail, this option is <em>disabled</em> by default.</p>"
03752               "<p>However, if you wish to, for example, view images in HTML "
03753               "messages that were not attached to it, you can enable this "
03754               "option, but you should be aware of the possible problem.</p></qt>" );
03755 
03756   QString receiptWhatsThis = i18n( "<qt><h3>Message Disposition "
03757               "Notification Policy</h3>"
03758               "<p>MDNs are a generalization of what is commonly called <b>read "
03759               "receipt</b>. The message author requests a disposition "
03760               "notification to be sent and the receiver's mail program "
03761               "generates a reply from which the author can learn what "
03762               "happened to his message. Common disposition types include "
03763               "<b>displayed</b> (i.e. read), <b>deleted</b> and <b>dispatched</b> "
03764               "(e.g. forwarded).</p>"
03765               "<p>The following options are available to control KMail's "
03766               "sending of MDNs:</p>"
03767               "<ul>"
03768               "<li><em>Ignore</em>: Ignores any request for disposition "
03769               "notifications. No MDN will ever be sent automatically "
03770               "(recommended).</li>"
03771               "<li><em>Ask</em>: Answers requests only after asking the user "
03772               "for permission. This way, you can send MDNs for selected "
03773               "messages while denying or ignoring them for others.</li>"
03774               "<li><em>Deny</em>: Always sends a <b>denied</b> notification. This "
03775               "is only <em>slightly</em> better than always sending MDNs. "
03776               "The author will still know that the messages has been acted "
03777               "upon, he just cannot tell whether it was deleted or read etc.</li>"
03778               "<li><em>Always send</em>: Always sends the requested "
03779               "disposition notification. That means that the author of the "
03780               "message gets to know when the message was acted upon and, "
03781               "in addition, what happened to it (displayed, deleted, "
03782               "etc.). This option is strongly discouraged, but since it "
03783               "makes much sense e.g. for customer relationship management, "
03784               "it has been made available.</li>"
03785               "</ul></qt>" );
03786 
03787 
03788   // "HTML Messages" group box:
03789   group = new QVGroupBox( i18n( "HTML Messages" ), this );
03790   group->layout()->setSpacing( KDialog::spacingHint() );
03791 
03792   mHtmlMailCheck = new QCheckBox( i18n("Prefer H&TML to plain text"), group );
03793   QWhatsThis::add( mHtmlMailCheck, htmlWhatsThis );
03794   connect( mHtmlMailCheck, SIGNAL( stateChanged( int ) ),
03795            this, SLOT( slotEmitChanged( void ) ) );
03796   mExternalReferences = new QCheckBox( i18n("Allow messages to load e&xternal "
03797                                             "references from the Internet" ), group );
03798   QWhatsThis::add( mExternalReferences, externalWhatsThis );
03799   connect( mExternalReferences, SIGNAL( stateChanged( int ) ),
03800            this, SLOT( slotEmitChanged( void ) ) );
03801   label = new KActiveLabel( i18n("<b>WARNING:</b> Allowing HTML in email may "
03802                            "increase the risk that your system will be "
03803                            "compromised by present and anticipated security "
03804                            "exploits. <a href=\"whatsthis:%1\">More about "
03805                            "HTML mails...</a> <a href=\"whatsthis:%2\">More "
03806                            "about external references...</a>")
03807                            .arg(htmlWhatsThis).arg(externalWhatsThis),
03808                            group );
03809 
03810   vlay->addWidget( group );
03811 
03812   // encrypted messages group
03813   group = new QVGroupBox( i18n("Encrypted Messages"), this );
03814   group->layout()->setSpacing( KDialog::spacingHint() );
03815   mAlwaysDecrypt = new QCheckBox( i18n( "Attempt decryption of encrypted messages when viewing" ), group );
03816   connect( mAlwaysDecrypt, SIGNAL(stateChanged(int)), this, SLOT(slotEmitChanged()) );
03817   vlay->addWidget( group );
03818 
03819   // "Message Disposition Notification" groupbox:
03820   group = new QVGroupBox( i18n("Message Disposition Notifications"), this );
03821   group->layout()->setSpacing( KDialog::spacingHint() );
03822 
03823 
03824   // "ignore", "ask", "deny", "always send" radiobutton line:
03825   mMDNGroup = new QButtonGroup( group );
03826   mMDNGroup->hide();
03827   connect( mMDNGroup, SIGNAL( clicked( int ) ),
03828            this, SLOT( slotEmitChanged( void ) ) );
03829   hbox = new QHBox( group );
03830   hbox->setSpacing( KDialog::spacingHint() );
03831 
03832   (void)new QLabel( i18n("Send policy:"), hbox );
03833 
03834   radio = new QRadioButton( i18n("&Ignore"), hbox );
03835   mMDNGroup->insert( radio );
03836 
03837   radio = new QRadioButton( i18n("As&k"), hbox );
03838   mMDNGroup->insert( radio );
03839 
03840   radio = new QRadioButton( i18n("&Deny"), hbox );
03841   mMDNGroup->insert( radio );
03842 
03843   radio = new QRadioButton( i18n("Al&ways send"), hbox );
03844   mMDNGroup->insert( radio );
03845 
03846   for ( int i = 0 ; i < mMDNGroup->count() ; ++i )
03847       QWhatsThis::add( mMDNGroup->find( i ), receiptWhatsThis );
03848 
03849   w = new QWidget( hbox ); // spacer
03850   hbox->setStretchFactor( w, 1 );
03851 
03852   // "Original Message quote" radiobutton line:
03853   mOrigQuoteGroup = new QButtonGroup( group );
03854   mOrigQuoteGroup->hide();
03855   connect( mOrigQuoteGroup, SIGNAL( clicked( int ) ),
03856            this, SLOT( slotEmitChanged( void ) ) );
03857 
03858   hbox = new QHBox( group );
03859   hbox->setSpacing( KDialog::spacingHint() );
03860 
03861   (void)new QLabel( i18n("Quote original message:"), hbox );
03862 
03863   radio = new QRadioButton( i18n("Nothin&g"), hbox );
03864   mOrigQuoteGroup->insert( radio );
03865 
03866   radio = new QRadioButton( i18n("&Full message"), hbox );
03867   mOrigQuoteGroup->insert( radio );
03868 
03869   radio = new QRadioButton( i18n("Onl&y headers"), hbox );
03870   mOrigQuoteGroup->insert( radio );
03871 
03872   w = new QWidget( hbox );
03873   hbox->setStretchFactor( w, 1 );
03874 
03875   mNoMDNsWhenEncryptedCheck = new QCheckBox( i18n("Do not send MDNs in response to encrypted messages"), group );
03876   connect( mNoMDNsWhenEncryptedCheck, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
03877 
03878   // Warning label:
03879   label = new KActiveLabel( i18n("<b>WARNING:</b> Unconditionally returning "
03880                            "confirmations undermines your privacy. "
03881                            "<a href=\"whatsthis:%1\">More...</a>")
03882                              .arg(receiptWhatsThis),
03883                            group );
03884 
03885   vlay->addWidget( group );
03886 
03887   // "Attached keys" group box:
03888   group = new QVGroupBox( i18n( "Certificate && Key Bundle Attachments" ), this );
03889   group->layout()->setSpacing( KDialog::spacingHint() );
03890 
03891   mAutomaticallyImportAttachedKeysCheck = new QCheckBox( i18n("Automatically import keys and certificates"), group );
03892   connect( mAutomaticallyImportAttachedKeysCheck, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
03893 
03894   vlay->addWidget( group );
03895 
03896 
03897 
03898   vlay->addStretch( 10 ); // spacer
03899 }
03900 
03901 void SecurityPage::GeneralTab::doLoadOther() {
03902   const KConfigGroup reader( KMKernel::config(), "Reader" );
03903 
03904   mHtmlMailCheck->setChecked( reader.readBoolEntry( "htmlMail", false ) );
03905   mExternalReferences->setChecked( reader.readBoolEntry( "htmlLoadExternal", false ) );
03906   mAutomaticallyImportAttachedKeysCheck->setChecked( reader.readBoolEntry( "AutoImportKeys", false ) );
03907 
03908   mAlwaysDecrypt->setChecked( GlobalSettings::self()->alwaysDecrypt() );
03909 
03910   const KConfigGroup mdn( KMKernel::config(), "MDN" );
03911 
03912   int num = mdn.readNumEntry( "default-policy", 0 );
03913   if ( num < 0 || num >= mMDNGroup->count() ) num = 0;
03914   mMDNGroup->setButton( num );
03915   num = mdn.readNumEntry( "quote-message", 0 );
03916   if ( num < 0 || num >= mOrigQuoteGroup->count() ) num = 0;
03917   mOrigQuoteGroup->setButton( num );
03918   mNoMDNsWhenEncryptedCheck->setChecked(mdn.readBoolEntry( "not-send-when-encrypted", true ));
03919 }
03920 
03921 void SecurityPage::GeneralTab::installProfile( KConfig * profile ) {
03922   const KConfigGroup reader( profile, "Reader" );
03923   const KConfigGroup mdn( profile, "MDN" );
03924 
03925   if ( reader.hasKey( "htmlMail" ) )
03926     mHtmlMailCheck->setChecked( reader.readBoolEntry( "htmlMail" ) );
03927   if ( reader.hasKey( "htmlLoadExternal" ) )
03928     mExternalReferences->setChecked( reader.readBoolEntry( "htmlLoadExternal" ) );
03929   if ( reader.hasKey( "AutoImportKeys" ) )
03930     mAutomaticallyImportAttachedKeysCheck->setChecked( reader.readBoolEntry( "AutoImportKeys" ) );
03931 
03932   if ( mdn.hasKey( "default-policy" ) ) {
03933       int num = mdn.readNumEntry( "default-policy" );
03934       if ( num < 0 || num >= mMDNGroup->count() ) num = 0;
03935       mMDNGroup->setButton( num );
03936   }
03937   if ( mdn.hasKey( "quote-message" ) ) {
03938       int num = mdn.readNumEntry( "quote-message" );
03939       if ( num < 0 || num >= mOrigQuoteGroup->count() ) num = 0;
03940       mOrigQuoteGroup->setButton( num );
03941   }
03942   if ( mdn.hasKey( "not-send-when-encrypted" ) )
03943       mNoMDNsWhenEncryptedCheck->setChecked(mdn.readBoolEntry( "not-send-when-encrypted" ));
03944 }
03945 
03946 void SecurityPage::GeneralTab::save() {
03947   KConfigGroup reader( KMKernel::config(), "Reader" );
03948   KConfigGroup mdn( KMKernel::config(), "MDN" );
03949 
03950   if (reader.readBoolEntry( "htmlMail", false ) != mHtmlMailCheck->isChecked())
03951   {
03952     if (KMessageBox::warningContinueCancel(this, i18n("Changing the global "
03953       "HTML setting will override all folder specific values."), QString::null,
03954       KStdGuiItem::cont(), "htmlMailOverride") == KMessageBox::Continue)
03955     {
03956       reader.writeEntry( "htmlMail", mHtmlMailCheck->isChecked() );
03957       QStringList names;
03958       QValueList<QGuardedPtr<KMFolder> > folders;
03959       kmkernel->folderMgr()->createFolderList(&names, &folders);
03960       kmkernel->imapFolderMgr()->createFolderList(&names, &folders);
03961       kmkernel->dimapFolderMgr()->createFolderList(&names, &folders);
03962       kmkernel->searchFolderMgr()->createFolderList(&names, &folders);
03963       for (QValueList<QGuardedPtr<KMFolder> >::iterator it = folders.begin();
03964         it != folders.end(); ++it)
03965       {
03966         if (*it)
03967         {
03968           KConfigGroupSaver saver(KMKernel::config(),
03969             "Folder-" + (*it)->idString());
03970           KMKernel::config()->writeEntry("htmlMailOverride", false);
03971         }
03972       }
03973     }
03974   }
03975   reader.writeEntry( "htmlLoadExternal", mExternalReferences->isChecked() );
03976   reader.writeEntry( "AutoImportKeys", mAutomaticallyImportAttachedKeysCheck->isChecked() );
03977   mdn.writeEntry( "default-policy", mMDNGroup->id( mMDNGroup->selected() ) );
03978   mdn.writeEntry( "quote-message", mOrigQuoteGroup->id( mOrigQuoteGroup->selected() ) );
03979   mdn.writeEntry( "not-send-when-encrypted", mNoMDNsWhenEncryptedCheck->isChecked() );
03980   GlobalSettings::self()->setAlwaysDecrypt( mAlwaysDecrypt->isChecked() );
03981 }
03982 
03983 
03984 QString SecurityPage::ComposerCryptoTab::helpAnchor() const {
03985   return QString::fromLatin1("configure-security-composing");
03986 }
03987 
03988 SecurityPageComposerCryptoTab::SecurityPageComposerCryptoTab( QWidget * parent, const char * name )
03989   : ConfigModuleTab ( parent, name )
03990 {
03991   // the margins are inside mWidget itself
03992   QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 );
03993 
03994   mWidget = new ComposerCryptoConfiguration( this );
03995   connect( mWidget->mAutoSignature, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03996   connect( mWidget->mEncToSelf, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03997   connect( mWidget->mShowEncryptionResult, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03998   connect( mWidget->mShowKeyApprovalDlg, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03999   connect( mWidget->mAutoEncrypt, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
04000   connect( mWidget->mNeverEncryptWhenSavingInDrafts, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
04001   connect( mWidget->mStoreEncrypted, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
04002   vlay->addWidget( mWidget );
04003 }
04004 
04005 void SecurityPage::ComposerCryptoTab::doLoadOther() {
04006   const KConfigGroup composer( KMKernel::config(), "Composer" );
04007 
04008   // If you change default values, sync messagecomposer.cpp too
04009 
04010   mWidget->mAutoSignature->setChecked( composer.readBoolEntry( "pgp-auto-sign", false ) );
04011 
04012   mWidget->mEncToSelf->setChecked( composer.readBoolEntry( "crypto-encrypt-to-self", true ) );
04013   mWidget->mShowEncryptionResult->setChecked( false ); //composer.readBoolEntry( "crypto-show-encryption-result", true ) );
04014   mWidget->mShowEncryptionResult->hide();
04015   mWidget->mShowKeyApprovalDlg->setChecked( composer.readBoolEntry( "crypto-show-keys-for-approval", true ) );
04016 
04017   mWidget->mAutoEncrypt->setChecked( composer.readBoolEntry( "pgp-auto-encrypt", false ) );
04018   mWidget->mNeverEncryptWhenSavingInDrafts->setChecked( composer.readBoolEntry( "never-encrypt-drafts", true ) );
04019 
04020   mWidget->mStoreEncrypted->setChecked( composer.readBoolEntry( "crypto-store-encrypted", true ) );
04021 }
04022 
04023 void SecurityPage::ComposerCryptoTab::installProfile( KConfig * profile ) {
04024   const KConfigGroup composer( profile, "Composer" );
04025 
04026   if ( composer.hasKey( "pgp-auto-sign" ) )
04027     mWidget->mAutoSignature->setChecked( composer.readBoolEntry( "pgp-auto-sign" ) );
04028 
04029   if ( composer.hasKey( "crypto-encrypt-to-self" ) )
04030     mWidget->mEncToSelf->setChecked( composer.readBoolEntry( "crypto-encrypt-to-self" ) );
04031   if ( composer.hasKey( "crypto-show-encryption-result" ) )
04032     mWidget->mShowEncryptionResult->setChecked( composer.readBoolEntry( "crypto-show-encryption-result" ) );
04033   if ( composer.hasKey( "crypto-show-keys-for-approval" ) )
04034     mWidget->mShowKeyApprovalDlg->setChecked( composer.readBoolEntry( "crypto-show-keys-for-approval" ) );
04035   if ( composer.hasKey( "pgp-auto-encrypt" ) )
04036     mWidget->mAutoEncrypt->setChecked( composer.readBoolEntry( "pgp-auto-encrypt" ) );
04037   if ( composer.hasKey( "never-encrypt-drafts" ) )
04038     mWidget->mNeverEncryptWhenSavingInDrafts->setChecked( composer.readBoolEntry( "never-encrypt-drafts" ) );
04039 
04040   if ( composer.hasKey( "crypto-store-encrypted" ) )
04041     mWidget->mStoreEncrypted->setChecked( composer.readBoolEntry( "crypto-store-encrypted" ) );
04042 }
04043 
04044 void SecurityPage::ComposerCryptoTab::save() {
04045   KConfigGroup composer( KMKernel::config(), "Composer" );
04046 
04047   composer.writeEntry( "pgp-auto-sign", mWidget->mAutoSignature->isChecked() );
04048 
04049   composer.writeEntry( "crypto-encrypt-to-self", mWidget->mEncToSelf->isChecked() );
04050   composer.writeEntry( "crypto-show-encryption-result", mWidget->mShowEncryptionResult->isChecked() );
04051   composer.writeEntry( "crypto-show-keys-for-approval", mWidget->mShowKeyApprovalDlg->isChecked() );
04052 
04053   composer.writeEntry( "pgp-auto-encrypt", mWidget->mAutoEncrypt->isChecked() );
04054   composer.writeEntry( "never-encrypt-drafts", mWidget->mNeverEncryptWhenSavingInDrafts->isChecked() );
04055 
04056   composer.writeEntry( "crypto-store-encrypted", mWidget->mStoreEncrypted->isChecked() );
04057 }
04058 
04059 QString SecurityPage::WarningTab::helpAnchor() const {
04060   return QString::fromLatin1("configure-security-warnings");
04061 }
04062 
04063 SecurityPageWarningTab::SecurityPageWarningTab( QWidget * parent, const char * name )
04064   : ConfigModuleTab( parent, name )
04065 {
04066   // the margins are inside mWidget itself
04067   QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 );
04068 
04069   mWidget = new WarningConfiguration( this );
04070   vlay->addWidget( mWidget );
04071 
04072   connect( mWidget->warnGroupBox, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
04073   connect( mWidget->mWarnUnsigned, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
04074   connect( mWidget->warnUnencryptedCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
04075   connect( mWidget->warnReceiverNotInCertificateCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
04076   connect( mWidget->mWarnSignKeyExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
04077   connect( mWidget->mWarnSignChainCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
04078   connect( mWidget->mWarnSignRootCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
04079 
04080   connect( mWidget->mWarnEncrKeyExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
04081   connect( mWidget->mWarnEncrChainCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
04082   connect( mWidget->mWarnEncrRootCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
04083 
04084   connect( mWidget->enableAllWarningsPB, SIGNAL(clicked()),
04085            SLOT(slotReenableAllWarningsClicked()) );
04086 }
04087 
04088 void SecurityPage::WarningTab::doLoadOther() {
04089   const KConfigGroup composer( KMKernel::config(), "Composer" );
04090 
04091   mWidget->warnUnencryptedCB->setChecked( composer.readBoolEntry( "crypto-warning-unencrypted", false ) );
04092   mWidget->mWarnUnsigned->setChecked( composer.readBoolEntry( "crypto-warning-unsigned", false ) );
04093   mWidget->warnReceiverNotInCertificateCB->setChecked( composer.readBoolEntry( "crypto-warn-recv-not-in-cert", true ) );
04094 
04095   // The "-int" part of the key name is because there used to be a separate boolean
04096   // config entry for enabling/disabling. This is done with the single bool value now.
04097   mWidget->warnGroupBox->setChecked( composer.readBoolEntry( "crypto-warn-when-near-expire", true ) );
04098 
04099   mWidget->mWarnSignKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-key-near-expire-int", 14 ) );
04100   mWidget->mWarnSignChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int", 14 ) );
04101   mWidget->mWarnSignRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-root-near-expire-int", 14 ) );
04102 
04103   mWidget->mWarnEncrKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-key-near-expire-int", 14 ) );
04104   mWidget->mWarnEncrChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int", 14 ) );
04105   mWidget->mWarnEncrRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-root-near-expire-int", 14 ) );
04106 
04107   mWidget->enableAllWarningsPB->setEnabled( true );
04108 }
04109 
04110 void SecurityPage::WarningTab::installProfile( KConfig * profile ) {
04111   const KConfigGroup composer( profile, "Composer" );
04112 
04113   if ( composer.hasKey( "crypto-warning-unencrypted" ) )
04114     mWidget->warnUnencryptedCB->setChecked( composer.readBoolEntry( "crypto-warning-unencrypted" ) );
04115   if ( composer.hasKey( "crypto-warning-unsigned" ) )
04116     mWidget->mWarnUnsigned->setChecked( composer.readBoolEntry( "crypto-warning-unsigned" ) );
04117   if ( composer.hasKey( "crypto-warn-recv-not-in-cert" ) )
04118     mWidget->warnReceiverNotInCertificateCB->setChecked( composer.readBoolEntry( "crypto-warn-recv-not-in-cert" ) );
04119 
04120   if ( composer.hasKey( "crypto-warn-when-near-expire" ) )
04121     mWidget->warnGroupBox->setChecked( composer.readBoolEntry( "crypto-warn-when-near-expire" ) );
04122 
04123   if ( composer.hasKey( "crypto-warn-sign-key-near-expire-int" ) )
04124     mWidget->mWarnSignKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-key-near-expire-int" ) );
04125   if ( composer.hasKey( "crypto-warn-sign-chaincert-near-expire-int" ) )
04126     mWidget->mWarnSignChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int" ) );
04127   if ( composer.hasKey( "crypto-warn-sign-root-near-expire-int" ) )
04128     mWidget->mWarnSignRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-root-near-expire-int" ) );
04129 
04130   if ( composer.hasKey( "crypto-warn-encr-key-near-expire-int" ) )
04131     mWidget->mWarnEncrKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-key-near-expire-int" ) );
04132   if ( composer.hasKey( "crypto-warn-encr-chaincert-near-expire-int" ) )
04133     mWidget->mWarnEncrChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int" ) );
04134   if ( composer.hasKey( "crypto-warn-encr-root-near-expire-int" ) )
04135     mWidget->mWarnEncrRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-root-near-expire-int" ) );
04136 }
04137 
04138 void SecurityPage::WarningTab::save() {
04139   KConfigGroup composer( KMKernel::config(), "Composer" );
04140 
04141   composer.writeEntry( "crypto-warn-recv-not-in-cert", mWidget->warnReceiverNotInCertificateCB->isChecked() );
04142   composer.writeEntry( "crypto-warning-unencrypted", mWidget->warnUnencryptedCB->isChecked() );
04143   composer.writeEntry( "crypto-warning-unsigned", mWidget->mWarnUnsigned->isChecked() );
04144 
04145   composer.writeEntry( "crypto-warn-when-near-expire", mWidget->warnGroupBox->isChecked() );
04146   composer.writeEntry( "crypto-warn-sign-key-near-expire-int",
04147                        mWidget->mWarnSignKeyExpiresSB->value() );
04148   composer.writeEntry( "crypto-warn-sign-chaincert-near-expire-int",
04149                        mWidget->mWarnSignChainCertExpiresSB->value() );
04150   composer.writeEntry( "crypto-warn-sign-root-near-expire-int",
04151                        mWidget->mWarnSignRootCertExpiresSB->value() );
04152 
04153   composer.writeEntry( "crypto-warn-encr-key-near-expire-int",
04154                        mWidget->mWarnEncrKeyExpiresSB->value() );
04155   composer.writeEntry( "crypto-warn-encr-chaincert-near-expire-int",
04156                        mWidget->mWarnEncrChainCertExpiresSB->value() );
04157   composer.writeEntry( "crypto-warn-encr-root-near-expire-int",
04158                        mWidget->mWarnEncrRootCertExpiresSB->value() );
04159 }
04160 
04161 void SecurityPage::WarningTab::slotReenableAllWarningsClicked() {
04162   KMessageBox::enableAllMessages();
04163   mWidget->enableAllWarningsPB->setEnabled( false );
04164 }
04165 
04167 
04168 QString SecurityPage::SMimeTab::helpAnchor() const {
04169   return QString::fromLatin1("configure-security-smime-validation");
04170 }
04171 
04172 SecurityPageSMimeTab::SecurityPageSMimeTab( QWidget * parent, const char * name )
04173   : ConfigModuleTab( parent, name )
04174 {
04175   // the margins are inside mWidget itself
04176   QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 );
04177 
04178   mWidget = new SMimeConfiguration( this );
04179   vlay->addWidget( mWidget );
04180 
04181   // Button-group for exclusive radiobuttons
04182   QButtonGroup* bg = new QButtonGroup( mWidget );
04183   bg->hide();
04184   bg->insert( mWidget->CRLRB );
04185   bg->insert( mWidget->OCSPRB );
04186 
04187   // Settings for the keyrequester custom widget
04188   mWidget->OCSPResponderSignature->setAllowedKeys(
04189      Kleo::KeySelectionDialog::SMIMEKeys
04190      | Kleo::KeySelectionDialog::TrustedKeys
04191      | Kleo::KeySelectionDialog::ValidKeys
04192      | Kleo::KeySelectionDialog::SigningKeys
04193      | Kleo::KeySelectionDialog::PublicKeys );
04194   mWidget->OCSPResponderSignature->setMultipleKeysEnabled( false );
04195 
04196   mConfig = Kleo::CryptoBackendFactory::instance()->config();
04197 
04198   connect( mWidget->CRLRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04199   connect( mWidget->OCSPRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04200   connect( mWidget->OCSPResponderURL, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) );
04201   connect( mWidget->OCSPResponderSignature, SIGNAL( changed() ), this, SLOT( slotEmitChanged() ) );
04202   connect( mWidget->doNotCheckCertPolicyCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04203   connect( mWidget->neverConsultCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04204   connect( mWidget->fetchMissingCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04205 
04206   connect( mWidget->ignoreServiceURLCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04207   connect( mWidget->ignoreHTTPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04208   connect( mWidget->disableHTTPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04209   connect( mWidget->honorHTTPProxyRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04210   connect( mWidget->useCustomHTTPProxyRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04211   connect( mWidget->customHTTPProxy, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) );
04212   connect( mWidget->ignoreLDAPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04213   connect( mWidget->disableLDAPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04214   connect( mWidget->customLDAPProxy, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) );
04215 
04216   connect( mWidget->disableHTTPCB, SIGNAL( toggled( bool ) ),
04217            this, SLOT( slotUpdateHTTPActions() ) );
04218   connect( mWidget->ignoreHTTPDPCB, SIGNAL( toggled( bool ) ),
04219            this, SLOT( slotUpdateHTTPActions() ) );
04220 
04221   // Button-group for exclusive radiobuttons
04222   QButtonGroup* bgHTTPProxy = new QButtonGroup( mWidget );
04223   bgHTTPProxy->hide();
04224   bgHTTPProxy->insert( mWidget->honorHTTPProxyRB );
04225   bgHTTPProxy->insert( mWidget->useCustomHTTPProxyRB );
04226 
04227   if ( !connectDCOPSignal( 0, "KPIM::CryptoConfig", "changed()",
04228                            "load()", false ) )
04229     kdError(5650) << "SecurityPageSMimeTab: connection to CryptoConfig's changed() failed" << endl;
04230 
04231 }
04232 
04233 SecurityPageSMimeTab::~SecurityPageSMimeTab()
04234 {
04235 }
04236 
04237 static void disableDirmngrWidget( QWidget* w ) {
04238   w->setEnabled( false );
04239   QWhatsThis::remove( w );
04240   QWhatsThis::add( w, i18n( "This option requires dirmngr >= 0.9.0" ) );
04241 }
04242 
04243 static void initializeDirmngrCheckbox( QCheckBox* cb, Kleo::CryptoConfigEntry* entry ) {
04244   if ( entry )
04245     cb->setChecked( entry->boolValue() );
04246   else
04247     disableDirmngrWidget( cb );
04248 }
04249 
04250 struct SMIMECryptoConfigEntries {
04251   SMIMECryptoConfigEntries( Kleo::CryptoConfig* config )
04252     : mConfig( config ) {
04253 
04254     // Checkboxes
04255     mCheckUsingOCSPConfigEntry = configEntry( "gpgsm", "Security", "enable-ocsp", Kleo::CryptoConfigEntry::ArgType_None, false );
04256     mEnableOCSPsendingConfigEntry = configEntry( "dirmngr", "OCSP", "allow-ocsp", Kleo::CryptoConfigEntry::ArgType_None, false );
04257     mDoNotCheckCertPolicyConfigEntry = configEntry( "gpgsm", "Security", "disable-policy-checks", Kleo::CryptoConfigEntry::ArgType_None, false );
04258     mNeverConsultConfigEntry = configEntry( "gpgsm", "Security", "disable-crl-checks", Kleo::CryptoConfigEntry::ArgType_None, false );
04259     mFetchMissingConfigEntry = configEntry( "gpgsm", "Security", "auto-issuer-key-retrieve", Kleo::CryptoConfigEntry::ArgType_None, false );
04260     // dirmngr-0.9.0 options
04261     mIgnoreServiceURLEntry = configEntry( "dirmngr", "OCSP", "ignore-ocsp-service-url", Kleo::CryptoConfigEntry::ArgType_None, false );
04262     mIgnoreHTTPDPEntry = configEntry( "dirmngr", "HTTP", "ignore-http-dp", Kleo::CryptoConfigEntry::ArgType_None, false );
04263     mDisableHTTPEntry = configEntry( "dirmngr", "HTTP", "disable-http", Kleo::CryptoConfigEntry::ArgType_None, false );
04264     mHonorHTTPProxy = configEntry( "dirmngr", "HTTP", "honor-http-proxy", Kleo::CryptoConfigEntry::ArgType_None, false );
04265 
04266     mIgnoreLDAPDPEntry = configEntry( "dirmngr", "LDAP", "ignore-ldap-dp", Kleo::CryptoConfigEntry::ArgType_None, false );
04267     mDisableLDAPEntry = configEntry( "dirmngr", "LDAP", "disable-ldap", Kleo::CryptoConfigEntry::ArgType_None, false );
04268     // Other widgets
04269     mOCSPResponderURLConfigEntry = configEntry( "dirmngr", "OCSP", "ocsp-responder", Kleo::CryptoConfigEntry::ArgType_String, false );
04270     mOCSPResponderSignature = configEntry( "dirmngr", "OCSP", "ocsp-signer", Kleo::CryptoConfigEntry::ArgType_String, false );
04271     mCustomHTTPProxy = configEntry( "dirmngr", "HTTP", "http-proxy", Kleo::CryptoConfigEntry::ArgType_String, false );
04272     mCustomLDAPProxy = configEntry( "dirmngr", "LDAP", "ldap-proxy", Kleo::CryptoConfigEntry::ArgType_String, false );
04273   }
04274 
04275   Kleo::CryptoConfigEntry* configEntry( const char* componentName,
04276                                         const char* groupName,
04277                                         const char* entryName,
04278                                         int argType,
04279                                         bool isList );
04280 
04281   // Checkboxes
04282   Kleo::CryptoConfigEntry* mCheckUsingOCSPConfigEntry;
04283   Kleo::CryptoConfigEntry* mEnableOCSPsendingConfigEntry;
04284   Kleo::CryptoConfigEntry* mDoNotCheckCertPolicyConfigEntry;
04285   Kleo::CryptoConfigEntry* mNeverConsultConfigEntry;
04286   Kleo::CryptoConfigEntry* mFetchMissingConfigEntry;
04287   Kleo::CryptoConfigEntry* mIgnoreServiceURLEntry;
04288   Kleo::CryptoConfigEntry* mIgnoreHTTPDPEntry;
04289   Kleo::CryptoConfigEntry* mDisableHTTPEntry;
04290   Kleo::CryptoConfigEntry* mHonorHTTPProxy;
04291   Kleo::CryptoConfigEntry* mIgnoreLDAPDPEntry;
04292   Kleo::CryptoConfigEntry* mDisableLDAPEntry;
04293   // Other widgets
04294   Kleo::CryptoConfigEntry* mOCSPResponderURLConfigEntry;
04295   Kleo::CryptoConfigEntry* mOCSPResponderSignature;
04296   Kleo::CryptoConfigEntry* mCustomHTTPProxy;
04297   Kleo::CryptoConfigEntry* mCustomLDAPProxy;
04298 
04299   Kleo::CryptoConfig* mConfig;
04300 };
04301 
04302 void SecurityPage::SMimeTab::doLoadOther() {
04303   if ( !mConfig ) {
04304     setEnabled( false );
04305     return;
04306   }
04307 
04308   // Force re-parsing gpgconf data, in case e.g. kleopatra or "configure backend" was used
04309   // (which ends up calling us via dcop)
04310   mConfig->clear();
04311 
04312   // Create config entries
04313   // Don't keep them around, they'll get deleted by clear(), which could be
04314   // done by the "configure backend" button even before we save().
04315   SMIMECryptoConfigEntries e( mConfig );
04316 
04317   // Initialize GUI items from the config entries
04318 
04319   if ( e.mCheckUsingOCSPConfigEntry ) {
04320     bool b = e.mCheckUsingOCSPConfigEntry->boolValue();
04321     mWidget->OCSPRB->setChecked( b );
04322     mWidget->CRLRB->setChecked( !b );
04323     mWidget->OCSPGroupBox->setEnabled( b );
04324   } else {
04325     mWidget->OCSPGroupBox->setEnabled( false );
04326   }
04327   if ( e.mDoNotCheckCertPolicyConfigEntry )
04328     mWidget->doNotCheckCertPolicyCB->setChecked( e.mDoNotCheckCertPolicyConfigEntry->boolValue() );
04329   if ( e.mNeverConsultConfigEntry )
04330     mWidget->neverConsultCB->setChecked( e.mNeverConsultConfigEntry->boolValue() );
04331   if ( e.mFetchMissingConfigEntry )
04332     mWidget->fetchMissingCB->setChecked( e.mFetchMissingConfigEntry->boolValue() );
04333 
04334   if ( e.mOCSPResponderURLConfigEntry )
04335     mWidget->OCSPResponderURL->setText( e.mOCSPResponderURLConfigEntry->stringValue() );
04336   if ( e.mOCSPResponderSignature ) {
04337     mWidget->OCSPResponderSignature->setFingerprint( e.mOCSPResponderSignature->stringValue() );
04338   }
04339 
04340   // dirmngr-0.9.0 options
04341   initializeDirmngrCheckbox( mWidget->ignoreServiceURLCB, e.mIgnoreServiceURLEntry );
04342   initializeDirmngrCheckbox( mWidget->ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry );
04343   initializeDirmngrCheckbox( mWidget->disableHTTPCB, e.mDisableHTTPEntry );
04344   initializeDirmngrCheckbox( mWidget->ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry );
04345   initializeDirmngrCheckbox( mWidget->disableLDAPCB, e.mDisableLDAPEntry );
04346   if ( e.mCustomHTTPProxy ) {
04347     QString systemProxy = QString::fromLocal8Bit( getenv( "http_proxy" ) );
04348     if ( systemProxy.isEmpty() )
04349       systemProxy = i18n( "no proxy" );
04350     mWidget->systemHTTPProxy->setText( i18n( "(Current system setting: %1)" ).arg( systemProxy ) );
04351     bool honor = e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue();
04352     mWidget->honorHTTPProxyRB->setChecked( honor );
04353     mWidget->useCustomHTTPProxyRB->setChecked( !honor );
04354     mWidget->customHTTPProxy->setText( e.mCustomHTTPProxy->stringValue() );
04355   } else {
04356     disableDirmngrWidget( mWidget->honorHTTPProxyRB );
04357     disableDirmngrWidget( mWidget->useCustomHTTPProxyRB );
04358     disableDirmngrWidget( mWidget->systemHTTPProxy );
04359     disableDirmngrWidget( mWidget->customHTTPProxy );
04360   }
04361   if ( e.mCustomLDAPProxy )
04362     mWidget->customLDAPProxy->setText( e.mCustomLDAPProxy->stringValue() );
04363   else {
04364     disableDirmngrWidget( mWidget->customLDAPProxy );
04365     disableDirmngrWidget( mWidget->customLDAPLabel );
04366   }
04367   slotUpdateHTTPActions();
04368 }
04369 
04370 void SecurityPage::SMimeTab::slotUpdateHTTPActions() {
04371   mWidget->ignoreHTTPDPCB->setEnabled( !mWidget->disableHTTPCB->isChecked() );
04372 
04373   // The proxy settings only make sense when "Ignore HTTP CRL DPs of certificate" is checked.
04374   bool enableProxySettings = !mWidget->disableHTTPCB->isChecked()
04375                           && mWidget->ignoreHTTPDPCB->isChecked();
04376   mWidget->systemHTTPProxy->setEnabled( enableProxySettings );
04377   mWidget->useCustomHTTPProxyRB->setEnabled( enableProxySettings );
04378   mWidget->honorHTTPProxyRB->setEnabled( enableProxySettings );
04379   mWidget->customHTTPProxy->setEnabled( enableProxySettings );
04380 }
04381 
04382 void SecurityPage::SMimeTab::installProfile( KConfig * ) {
04383 }
04384 
04385 static void saveCheckBoxToKleoEntry( QCheckBox* cb, Kleo::CryptoConfigEntry* entry ) {
04386   const bool b = cb->isChecked();
04387   if ( entry && entry->boolValue() != b )
04388     entry->setBoolValue( b );
04389 }
04390 
04391 void SecurityPage::SMimeTab::save() {
04392   if ( !mConfig ) {
04393     return;
04394   }
04395   // Create config entries
04396   // Don't keep them around, they'll get deleted by clear(), which could be done by the
04397   // "configure backend" button.
04398   SMIMECryptoConfigEntries e( mConfig );
04399 
04400   bool b = mWidget->OCSPRB->isChecked();
04401   if ( e.mCheckUsingOCSPConfigEntry && e.mCheckUsingOCSPConfigEntry->boolValue() != b )
04402     e.mCheckUsingOCSPConfigEntry->setBoolValue( b );
04403   // Set allow-ocsp together with enable-ocsp
04404   if ( e.mEnableOCSPsendingConfigEntry && e.mEnableOCSPsendingConfigEntry->boolValue() != b )
04405     e.mEnableOCSPsendingConfigEntry->setBoolValue( b );
04406 
04407   saveCheckBoxToKleoEntry( mWidget->doNotCheckCertPolicyCB, e.mDoNotCheckCertPolicyConfigEntry );
04408   saveCheckBoxToKleoEntry( mWidget->neverConsultCB, e.mNeverConsultConfigEntry );
04409   saveCheckBoxToKleoEntry( mWidget->fetchMissingCB, e.mFetchMissingConfigEntry );
04410 
04411   QString txt = mWidget->OCSPResponderURL->text();
04412   if ( e.mOCSPResponderURLConfigEntry && e.mOCSPResponderURLConfigEntry->stringValue() != txt )
04413     e.mOCSPResponderURLConfigEntry->setStringValue( txt );
04414 
04415   txt = mWidget->OCSPResponderSignature->fingerprint();
04416   if ( e.mOCSPResponderSignature && e.mOCSPResponderSignature->stringValue() != txt ) {
04417     e.mOCSPResponderSignature->setStringValue( txt );
04418   }
04419 
04420   //dirmngr-0.9.0 options
04421   saveCheckBoxToKleoEntry( mWidget->ignoreServiceURLCB, e.mIgnoreServiceURLEntry );
04422   saveCheckBoxToKleoEntry( mWidget->ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry );
04423   saveCheckBoxToKleoEntry( mWidget->disableHTTPCB, e.mDisableHTTPEntry );
04424   saveCheckBoxToKleoEntry( mWidget->ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry );
04425   saveCheckBoxToKleoEntry( mWidget->disableLDAPCB, e.mDisableLDAPEntry );
04426   if ( e.mCustomHTTPProxy ) {
04427     const bool honor = mWidget->honorHTTPProxyRB->isChecked();
04428     if ( e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue() != honor )
04429         e.mHonorHTTPProxy->setBoolValue( honor );
04430 
04431     QString chosenProxy = mWidget->customHTTPProxy->text();
04432     if ( chosenProxy != e.mCustomHTTPProxy->stringValue() )
04433       e.mCustomHTTPProxy->setStringValue( chosenProxy );
04434   }
04435   txt = mWidget->customLDAPProxy->text();
04436   if ( e.mCustomLDAPProxy && e.mCustomLDAPProxy->stringValue() != txt )
04437     e.mCustomLDAPProxy->setStringValue( mWidget->customLDAPProxy->text() );
04438 
04439   mConfig->sync( true );
04440 }
04441 
04442 bool SecurityPageSMimeTab::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData)
04443 {
04444     if ( fun == "load()" ) {
04445         replyType = "void";
04446         load();
04447     } else {
04448         return DCOPObject::process( fun, data, replyType, replyData );
04449     }
04450     return true;
04451 }
04452 
04453 QCStringList SecurityPageSMimeTab::interfaces()
04454 {
04455   QCStringList ifaces = DCOPObject::interfaces();
04456   ifaces += "SecurityPageSMimeTab";
04457   return ifaces;
04458 }
04459 
04460 QCStringList SecurityPageSMimeTab::functions()
04461 {
04462   // Hide our slot, just because it's simpler to do so.
04463   return DCOPObject::functions();
04464 }
04465 
04466 Kleo::CryptoConfigEntry* SMIMECryptoConfigEntries::configEntry( const char* componentName,
04467                                                                 const char* groupName,
04468                                                                 const char* entryName,
04469                                                                 int /*Kleo::CryptoConfigEntry::ArgType*/ argType,
04470                                                                 bool isList )
04471 {
04472     Kleo::CryptoConfigEntry* entry = mConfig->entry( componentName, groupName, entryName );
04473     if ( !entry ) {
04474         kdWarning(5006) << QString( "Backend error: gpgconf doesn't seem to know the entry for %1/%2/%3" ).arg( componentName, groupName, entryName ) << endl;
04475         return 0;
04476     }
04477     if( entry->argType() != argType || entry->isList() != isList ) {
04478         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;
04479         return 0;
04480     }
04481     return entry;
04482 }
04483 
04485 
04486 QString SecurityPage::CryptPlugTab::helpAnchor() const {
04487   return QString::fromLatin1("configure-security-crypto-backends");
04488 }
04489 
04490 SecurityPageCryptPlugTab::SecurityPageCryptPlugTab( QWidget * parent, const char * name )
04491   : ConfigModuleTab( parent, name )
04492 {
04493   QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
04494 
04495   mBackendConfig = Kleo::CryptoBackendFactory::instance()->configWidget( this, "mBackendConfig" );
04496   connect( mBackendConfig, SIGNAL( changed( bool ) ), this, SIGNAL( changed( bool ) ) );
04497 
04498   vlay->addWidget( mBackendConfig );
04499 }
04500 
04501 SecurityPageCryptPlugTab::~SecurityPageCryptPlugTab()
04502 {
04503 
04504 }
04505 
04506 void SecurityPage::CryptPlugTab::doLoadOther() {
04507   mBackendConfig->load();
04508 }
04509 
04510 void SecurityPage::CryptPlugTab::save() {
04511   mBackendConfig->save();
04512 }
04513 
04514 // *************************************************************
04515 // *                                                           *
04516 // *                        MiscPage                           *
04517 // *                                                           *
04518 // *************************************************************
04519 QString MiscPage::helpAnchor() const {
04520   return QString::fromLatin1("configure-misc");
04521 }
04522 
04523 MiscPage::MiscPage( QWidget * parent, const char * name )
04524   : ConfigModuleWithTabs( parent, name )
04525 {
04526   mFolderTab = new FolderTab();
04527   addTab( mFolderTab, i18n("&Folders") );
04528 
04529   mGroupwareTab = new GroupwareTab();
04530   addTab( mGroupwareTab, i18n("&Groupware") );
04531   load();
04532 }
04533 
04534 QString MiscPage::FolderTab::helpAnchor() const {
04535   return QString::fromLatin1("configure-misc-folders");
04536 }
04537 
04538 MiscPageFolderTab::MiscPageFolderTab( QWidget * parent, const char * name )
04539   : ConfigModuleTab( parent, name )
04540 {
04541   // temp. vars:
04542   QVBoxLayout *vlay;
04543   QHBoxLayout *hlay;
04544   QLabel      *label;
04545 
04546   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
04547 
04548   // "confirm before emptying folder" check box: stretch 0
04549   mEmptyFolderConfirmCheck =
04550     new QCheckBox( i18n("Corresponds to Folder->Move All Messages to Trash",
04551                         "Ask for co&nfirmation before moving all messages to "
04552                         "trash"),
04553                    this );
04554   vlay->addWidget( mEmptyFolderConfirmCheck );
04555   connect( mEmptyFolderConfirmCheck, SIGNAL( stateChanged( int ) ),
04556            this, SLOT( slotEmitChanged( void ) ) );
04557   mExcludeImportantFromExpiry =
04558     new QCheckBox( i18n("E&xclude important messages from expiry"), this );
04559   vlay->addWidget( mExcludeImportantFromExpiry );
04560   connect( mExcludeImportantFromExpiry, SIGNAL( stateChanged( int ) ),
04561            this, SLOT( slotEmitChanged( void ) ) );
04562 
04563   // "when trying to find unread messages" combo + label: stretch 0
04564   hlay = new QHBoxLayout( vlay ); // inherits spacing
04565   mLoopOnGotoUnread = new QComboBox( false, this );
04566   label = new QLabel( mLoopOnGotoUnread,
04567            i18n("to be continued with \"do not loop\", \"loop in current folder\", "
04568                 "and \"loop in all folders\".",
04569                 "When trying to find unread messages:"), this );
04570   mLoopOnGotoUnread->insertStringList( QStringList()
04571       << i18n("continuation of \"When trying to find unread messages:\"",
04572               "Do not Loop")
04573       << i18n("continuation of \"When trying to find unread messages:\"",
04574               "Loop in Current Folder")
04575       << i18n("continuation of \"When trying to find unread messages:\"",
04576               "Loop in All Folders"));
04577   hlay->addWidget( label );
04578   hlay->addWidget( mLoopOnGotoUnread, 1 );
04579   connect( mLoopOnGotoUnread, SIGNAL( activated( int ) ),
04580            this, SLOT( slotEmitChanged( void ) ) );
04581 
04582   // when entering a folder
04583   hlay = new QHBoxLayout( vlay ); // inherits spacing
04584   mActionEnterFolder = new QComboBox( false, this );
04585   label = new QLabel( mActionEnterFolder,
04586            i18n("to be continued with \"jump to first new message\", "
04587                 "\"jump to first unread or new message\","
04588                 "and \"jump to last selected message\".",
04589                 "When entering a folder:"), this );
04590   mActionEnterFolder->insertStringList( QStringList()
04591       << i18n("continuation of \"When entering a folder:\"",
04592               "Jump to First New Message")
04593       << i18n("continuation of \"When entering a folder:\"",
04594               "Jump to First Unread or New Message")
04595       << i18n("continuation of \"When entering a folder:\"",
04596               "Jump to Last Selected Message")
04597       << i18n("continuation of \"When entering a folder:\"",
04598               "Jump to Newest Message")
04599       << i18n("continuation of \"When entering a folder:\"",
04600               "Jump to Oldest Message") );
04601   hlay->addWidget( label );
04602   hlay->addWidget( mActionEnterFolder, 1 );
04603   connect( mActionEnterFolder, SIGNAL( activated( int ) ),
04604            this, SLOT( slotEmitChanged( void ) ) );
04605 
04606   hlay = new QHBoxLayout( vlay ); // inherits spacing
04607   mDelayedMarkAsRead = new QCheckBox( i18n("Mar&k selected message as read after"), this );
04608   hlay->addWidget( mDelayedMarkAsRead );
04609   mDelayedMarkTime = new KIntSpinBox( 0 /*min*/, 60 /*max*/, 1/*step*/,
04610                                       0 /*init*/, 10 /*base*/, this);
04611   mDelayedMarkTime->setSuffix( i18n(" sec") );
04612   mDelayedMarkTime->setEnabled( false ); // since mDelayedMarkAsREad is off
04613   hlay->addWidget( mDelayedMarkTime );
04614   hlay->addStretch( 1 );
04615   connect( mDelayedMarkTime, SIGNAL( valueChanged( int ) ),
04616            this, SLOT( slotEmitChanged( void ) ) );
04617   connect( mDelayedMarkAsRead, SIGNAL(toggled(bool)),
04618            mDelayedMarkTime, SLOT(setEnabled(bool)));
04619   connect( mDelayedMarkAsRead, SIGNAL(toggled(bool)),
04620            this , SLOT(slotEmitChanged( void )));
04621 
04622   // "show popup after Drag'n'Drop" checkbox: stretch 0
04623   mShowPopupAfterDnD =
04624     new QCheckBox( i18n("Ask for action after &dragging messages to another folder"), this );
04625   vlay->addWidget( mShowPopupAfterDnD );
04626   connect( mShowPopupAfterDnD, SIGNAL( stateChanged( int ) ),
04627            this, SLOT( slotEmitChanged( void ) ) );
04628 
04629   // "default mailbox format" combo + label: stretch 0
04630   hlay = new QHBoxLayout( vlay ); // inherits spacing
04631   mMailboxPrefCombo = new QComboBox( false, this );
04632   label = new QLabel( mMailboxPrefCombo,
04633                       i18n("to be continued with \"flat files\" and "
04634                            "\"directories\", resp.",
04635                            "By default, &message folders on disk are:"), this );
04636   mMailboxPrefCombo->insertStringList( QStringList()
04637           << i18n("continuation of \"By default, &message folders on disk are\"",
04638                   "Flat Files (\"mbox\" format)")
04639           << i18n("continuation of \"By default, &message folders on disk are\"",
04640                   "Directories (\"maildir\" format)") );
04641   // and now: add QWhatsThis:
04642   QString msg = i18n( "what's this help",
04643                       "<qt><p>This selects which mailbox format will be "
04644                       "the default for local folders:</p>"
04645                       "<p><b>mbox:</b> KMail's mail "
04646                       "folders are represented by a single file each. "
04647                       "Individual messages are separated from each other by a "
04648                       "line starting with \"From \". This saves space on "
04649                       "disk, but may be less robust, e.g. when moving messages "
04650                       "between folders.</p>"
04651                       "<p><b>maildir:</b> KMail's mail folders are "
04652                       "represented by real folders on disk. Individual messages "
04653                       "are separate files. This may waste a bit of space on "
04654                       "disk, but should be more robust, e.g. when moving "
04655                       "messages between folders.</p></qt>");
04656   QWhatsThis::add( mMailboxPrefCombo, msg );
04657   QWhatsThis::add( label, msg );
04658   hlay->addWidget( label );
04659   hlay->addWidget( mMailboxPrefCombo, 1 );
04660   connect( mMailboxPrefCombo, SIGNAL( activated( int ) ),
04661            this, SLOT( slotEmitChanged( void ) ) );
04662 
04663   // "On startup..." option:
04664   hlay = new QHBoxLayout( vlay ); // inherits spacing
04665   mOnStartupOpenFolder = new FolderRequester( this,
04666       kmkernel->getKMMainWidget()->folderTree() );
04667   label = new QLabel( mOnStartupOpenFolder,
04668                       i18n("Open this folder on startup:"), this );
04669   hlay->addWidget( label );
04670   hlay->addWidget( mOnStartupOpenFolder, 1 );
04671   connect( mOnStartupOpenFolder, SIGNAL( folderChanged( KMFolder* ) ),
04672            this, SLOT( slotEmitChanged( void ) ) );
04673 
04674   // "Empty &trash on program exit" option:
04675   hlay = new QHBoxLayout( vlay ); // inherits spacing
04676   mEmptyTrashCheck = new QCheckBox( i18n("Empty local &trash folder on program exit"),
04677                                     this );
04678   hlay->addWidget( mEmptyTrashCheck );
04679   connect( mEmptyTrashCheck, SIGNAL( stateChanged( int ) ),
04680            this, SLOT( slotEmitChanged( void ) ) );
04681 
04682 #ifdef HAVE_INDEXLIB
04683   // indexing enabled option:
04684   mIndexingEnabled = new QCheckBox( i18n("Enable full text &indexing"), this );
04685   vlay->addWidget( mIndexingEnabled );
04686   connect( mIndexingEnabled, SIGNAL( stateChanged( int ) ),
04687            this, SLOT( slotEmitChanged( void ) ) );
04688 #endif
04689 
04690   // "Quota Units"
04691   hlay = new QHBoxLayout( vlay ); // inherits spacing
04692   mQuotaCmbBox = new QComboBox( false, this );
04693   label = new QLabel( mQuotaCmbBox,
04694                       i18n("Quota units: "), this );
04695   mQuotaCmbBox->insertStringList( QStringList()
04696                    << i18n("KB")
04697                    << i18n("MB")
04698                    << i18n("GB") );
04699   hlay->addWidget( label );
04700   hlay->addWidget( mQuotaCmbBox, 1 );
04701   connect( mQuotaCmbBox, SIGNAL( activated( int )  ), this, SLOT( slotEmitChanged( void ) ) );
04702 
04703   vlay->addStretch( 1 );
04704 
04705   // @TODO: Till, move into .kcgc file
04706   msg = i18n( "what's this help",
04707             "<qt><p>When jumping to the next unread message, it may occur "
04708             "that no more unread messages are below the current message.</p>"
04709             "<p><b>Do not loop:</b> The search will stop at the last message in "
04710             "the current folder.</p>"
04711             "<p><b>Loop in current folder:</b> The search will continue at the "
04712             "top of the message list, but not go to another folder.</p>"
04713             "<p><b>Loop in all folders:</b> The search will continue at the top of "
04714             "the message list. If no unread messages are found it will then continue "
04715             "to the next folder.</p>"
04716             "<p>Similarly, when searching for the previous unread message, "
04717             "the search will start from the bottom of the message list and continue to "
04718             "the previous folder depending on which option is selected.</p></qt>" );
04719   QWhatsThis::add( mLoopOnGotoUnread, msg );
04720 
04721 #ifdef HAVE_INDEXLIB
04722  // this is probably overly pessimistic
04723   msg = i18n( "what's this help",
04724           "<qt><p>Full text indexing allows very fast searches on the content "
04725           "of your messages. When enabled, the search dialog will work very fast. "
04726           "Also, the search tool bar will select messages based on content.</p>"
04727           "<p>It takes up a certain amount of disk space "
04728           "(about half the disk space for the messages).</p>"
04729           "<p>After enabling, the index will need to be built, but you can continue to use KMail "
04730           "while this operation is running.</p>"
04731           "</qt>"
04732         );
04733 
04734   QWhatsThis::add( mIndexingEnabled, msg );
04735 #endif
04736 }
04737 
04738 void MiscPage::FolderTab::doLoadFromGlobalSettings() {
04739   mExcludeImportantFromExpiry->setChecked( GlobalSettings::self()->excludeImportantMailFromExpiry() );
04740   // default = "Loop in current folder"
04741   mLoopOnGotoUnread->setCurrentItem( GlobalSettings::self()->loopOnGotoUnread() );
04742   mActionEnterFolder->setCurrentItem( GlobalSettings::self()->actionEnterFolder() );
04743   mDelayedMarkAsRead->setChecked( GlobalSettings::self()->delayedMarkAsRead() );
04744   mDelayedMarkTime->setValue( GlobalSettings::self()->delayedMarkTime() );
04745   mShowPopupAfterDnD->setChecked( GlobalSettings::self()->showPopupAfterDnD() );
04746   mQuotaCmbBox->setCurrentItem( GlobalSettings::self()->quotaUnit() );
04747 }
04748 
04749 void MiscPage::FolderTab::doLoadOther() {
04750   KConfigGroup general( KMKernel::config(), "General" );
04751 
04752   mEmptyTrashCheck->setChecked( general.readBoolEntry( "empty-trash-on-exit", true ) );
04753   mOnStartupOpenFolder->setFolder( general.readEntry( "startupFolder",
04754                                                   kmkernel->inboxFolder()->idString() ) );
04755   mEmptyFolderConfirmCheck->setChecked( general.readBoolEntry( "confirm-before-empty", true ) );
04756 
04757   int num = general.readNumEntry("default-mailbox-format", 1 );
04758   if ( num < 0 || num > 1 ) num = 1;
04759   mMailboxPrefCombo->setCurrentItem( num );
04760 
04761 #ifdef HAVE_INDEXLIB
04762   mIndexingEnabled->setChecked( kmkernel->msgIndex() && kmkernel->msgIndex()->isEnabled() );
04763 #endif
04764 }
04765 
04766 void MiscPage::FolderTab::save() {
04767   KConfigGroup general( KMKernel::config(), "General" );
04768 
04769   general.writeEntry( "empty-trash-on-exit", mEmptyTrashCheck->isChecked() );
04770   general.writeEntry( "confirm-before-empty", mEmptyFolderConfirmCheck->isChecked() );
04771   general.writeEntry( "default-mailbox-format", mMailboxPrefCombo->currentItem() );
04772   general.writeEntry( "startupFolder", mOnStartupOpenFolder->folder() ?
04773                                   mOnStartupOpenFolder->folder()->idString() : QString::null );
04774 
04775   GlobalSettings::self()->setDelayedMarkAsRead( mDelayedMarkAsRead->isChecked() );
04776   GlobalSettings::self()->setDelayedMarkTime( mDelayedMarkTime->value() );
04777   GlobalSettings::self()->setActionEnterFolder( mActionEnterFolder->currentItem() );
04778   GlobalSettings::self()->setLoopOnGotoUnread( mLoopOnGotoUnread->currentItem() );
04779   GlobalSettings::self()->setShowPopupAfterDnD( mShowPopupAfterDnD->isChecked() );
04780   GlobalSettings::self()->setExcludeImportantMailFromExpiry(
04781         mExcludeImportantFromExpiry->isChecked() );
04782   GlobalSettings::self()->setQuotaUnit( mQuotaCmbBox->currentItem() );
04783 #ifdef HAVE_INDEXLIB
04784   if ( kmkernel->msgIndex() ) kmkernel->msgIndex()->setEnabled( mIndexingEnabled->isChecked() );
04785 #endif
04786 }
04787 
04788 QString MiscPage::GroupwareTab::helpAnchor() const {
04789   return QString::fromLatin1("configure-misc-groupware");
04790 }
04791 
04792 MiscPageGroupwareTab::MiscPageGroupwareTab( QWidget* parent, const char* name )
04793   : ConfigModuleTab( parent, name )
04794 {
04795   QBoxLayout* vlay = new QVBoxLayout( this, KDialog::marginHint(),
04796                                       KDialog::spacingHint() );
04797   vlay->setAutoAdd( true );
04798 
04799   // IMAP resource setup
04800   QVGroupBox* b1 = new QVGroupBox( i18n("&IMAP Resource Folder Options"),
04801                                    this );
04802 
04803   mEnableImapResCB =
04804     new QCheckBox( i18n("&Enable IMAP resource functionality"), b1 );
04805   QToolTip::add( mEnableImapResCB,  i18n( "This enables the IMAP storage for "
04806                                           "the Kontact applications" ) );
04807   QWhatsThis::add( mEnableImapResCB,
04808         i18n( GlobalSettings::self()->theIMAPResourceEnabledItem()->whatsThis().utf8() ) );
04809   connect( mEnableImapResCB, SIGNAL( stateChanged( int ) ),
04810            this, SLOT( slotEmitChanged( void ) ) );
04811 
04812   mBox = new QWidget( b1 );
04813   QGridLayout* grid = new QGridLayout( mBox, 5, 2, 0, KDialog::spacingHint() );
04814   grid->setColStretch( 1, 1 );
04815   connect( mEnableImapResCB, SIGNAL( toggled(bool) ),
04816            mBox, SLOT( setEnabled(bool) ) );
04817 
04818   QLabel* storageFormatLA = new QLabel( i18n("&Format used for the groupware folders:"),
04819                                         mBox );
04820   QString toolTip = i18n( "Choose the format to use to store the contents of the groupware folders." );
04821   QString whatsThis = i18n( GlobalSettings::self()
04822         ->theIMAPResourceStorageFormatItem()->whatsThis().utf8() );
04823   grid->addWidget( storageFormatLA, 0, 0 );
04824   QToolTip::add( storageFormatLA, toolTip );
04825   QWhatsThis::add( storageFormatLA, whatsThis );
04826   mStorageFormatCombo = new QComboBox( false, mBox );
04827   storageFormatLA->setBuddy( mStorageFormatCombo );
04828   QStringList formatLst;
04829   formatLst << i18n("Deprecated Kolab1 (iCal/vCard)") << i18n("Kolab2 (XML)");
04830   mStorageFormatCombo->insertStringList( formatLst );
04831   grid->addWidget( mStorageFormatCombo, 0, 1 );
04832   QToolTip::add( mStorageFormatCombo, toolTip );
04833   QWhatsThis::add( mStorageFormatCombo, whatsThis );
04834   connect( mStorageFormatCombo, SIGNAL( activated( int ) ),
04835            this, SLOT( slotStorageFormatChanged( int ) ) );
04836 
04837   QLabel* languageLA = new QLabel( i18n("&Language of the groupware folders:"),
04838                                    mBox );
04839 
04840   toolTip = i18n( "Set the language of the folder names" );
04841   whatsThis = i18n( GlobalSettings::self()
04842         ->theIMAPResourceFolderLanguageItem()->whatsThis().utf8() );
04843   grid->addWidget( languageLA, 1, 0 );
04844   QToolTip::add( languageLA, toolTip );
04845   QWhatsThis::add( languageLA, whatsThis );
04846   mLanguageCombo = new QComboBox( false, mBox );
04847   languageLA->setBuddy( mLanguageCombo );
04848   QStringList lst;
04849   lst << i18n("English") << i18n("German") << i18n("French") << i18n("Dutch");
04850   mLanguageCombo->insertStringList( lst );
04851   grid->addWidget( mLanguageCombo, 1, 1 );
04852   QToolTip::add( mLanguageCombo, toolTip );
04853   QWhatsThis::add( mLanguageCombo, whatsThis );
04854   connect( mLanguageCombo, SIGNAL( activated( int ) ),
04855            this, SLOT( slotEmitChanged( void ) ) );
04856 
04857   mFolderComboLabel = new QLabel( mBox ); // text depends on storage format
04858   toolTip = i18n( "Set the parent of the resource folders" );
04859   whatsThis = i18n( GlobalSettings::self()->theIMAPResourceFolderParentItem()->whatsThis().utf8() );
04860   QToolTip::add( mFolderComboLabel, toolTip );
04861   QWhatsThis::add( mFolderComboLabel, whatsThis );
04862   grid->addWidget( mFolderComboLabel, 2, 0 );
04863 
04864   mFolderComboStack = new QWidgetStack( mBox );
04865   grid->addWidget( mFolderComboStack, 2, 1 );
04866 
04867   // First possibility in the widgetstack: a combo showing the list of all folders
04868   // This is used with the ical/vcard storage
04869   mFolderCombo = new FolderRequester( mBox,
04870       kmkernel->getKMMainWidget()->folderTree() );
04871   mFolderComboStack->addWidget( mFolderCombo, 0 );
04872   QToolTip::add( mFolderCombo, toolTip );
04873   QWhatsThis::add( mFolderCombo, whatsThis );
04874   connect( mFolderCombo, SIGNAL( folderChanged( KMFolder* ) ),
04875            this, SLOT( slotEmitChanged() ) );
04876 
04877   // Second possibility in the widgetstack: a combo showing the list of accounts
04878   // This is used with the kolab xml storage since the groupware folders
04879   // are always under the inbox.
04880   mAccountCombo = new KMail::AccountComboBox( mBox );
04881   mFolderComboStack->addWidget( mAccountCombo, 1 );
04882   QToolTip::add( mAccountCombo, toolTip );
04883   QWhatsThis::add( mAccountCombo, whatsThis );
04884   connect( mAccountCombo, SIGNAL( activated( int ) ),
04885            this, SLOT( slotEmitChanged() ) );
04886 
04887   mHideGroupwareFolders = new QCheckBox( i18n( "&Hide groupware folders" ),
04888                                          mBox, "HideGroupwareFoldersBox" );
04889   grid->addMultiCellWidget( mHideGroupwareFolders, 3, 3, 0, 0 );
04890   QToolTip::add( mHideGroupwareFolders,
04891                  i18n( "When this is checked, you will not see the IMAP "
04892                        "resource folders in the folder tree." ) );
04893   QWhatsThis::add( mHideGroupwareFolders, i18n( GlobalSettings::self()
04894            ->hideGroupwareFoldersItem()->whatsThis().utf8() ) );
04895   connect( mHideGroupwareFolders, SIGNAL( toggled( bool ) ),
04896            this, SLOT( slotEmitChanged() ) );
04897 
04898   mOnlyShowGroupwareFolders = new QCheckBox( i18n( "&Only show groupware folders for this account" ),
04899                                          mBox, "OnlyGroupwareFoldersBox" );
04900   grid->addMultiCellWidget( mOnlyShowGroupwareFolders, 3, 3, 1, 1 );
04901   QToolTip::add( mOnlyShowGroupwareFolders,
04902                  i18n( "When this is checked, you will not see normal  "
04903                        "mail folders in the folder tree for the account "
04904                        "configured for groupware." ) );
04905   QWhatsThis::add( mOnlyShowGroupwareFolders, i18n( GlobalSettings::self()
04906            ->showOnlyGroupwareFoldersForGroupwareAccountItem()->whatsThis().utf8() ) );
04907   connect( mOnlyShowGroupwareFolders, SIGNAL( toggled( bool ) ),
04908            this, SLOT( slotEmitChanged() ) );
04909 
04910   mSyncImmediately = new QCheckBox( i18n( "Synchronize groupware changes immediately" ), mBox );
04911   QToolTip::add( mSyncImmediately,
04912                  i18n( "Synchronize groupware changes in disconnected IMAP folders immediately when being online." ) );
04913   connect( mSyncImmediately, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
04914   grid->addMultiCellWidget( mSyncImmediately, 4, 4, 0, 1 );
04915 
04916   mDeleteInvitations = new QCheckBox(
04917              i18n( GlobalSettings::self()->deleteInvitationEmailsAfterSendingReplyItem()->label().utf8() ), mBox );
04918   QWhatsThis::add( mDeleteInvitations, i18n( GlobalSettings::self()
04919              ->deleteInvitationEmailsAfterSendingReplyItem()->whatsThis().utf8() ) );
04920     connect( mDeleteInvitations, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
04921     grid->addMultiCellWidget( mDeleteInvitations, 5, 5, 0, 1 );
04922 
04923   // Groupware functionality compatibility setup
04924   b1 = new QVGroupBox( i18n("Groupware Compatibility && Legacy Options"), this );
04925 
04926   gBox = new QVBox( b1 );
04927 #if 0
04928   // Currently believed to be disused.
04929   mEnableGwCB = new QCheckBox( i18n("&Enable groupware functionality"), b1 );
04930   gBox->setSpacing( KDialog::spacingHint() );
04931   connect( mEnableGwCB, SIGNAL( toggled(bool) ),
04932            gBox, SLOT( setEnabled(bool) ) );
04933   connect( mEnableGwCB, SIGNAL( stateChanged( int ) ),
04934            this, SLOT( slotEmitChanged( void ) ) );
04935 #endif
04936   mEnableGwCB = 0;
04937   mLegacyMangleFromTo = new QCheckBox( i18n( "Mangle From:/To: headers in replies to invitations" ), gBox );
04938   QToolTip::add( mLegacyMangleFromTo, i18n( "Turn this option on in order to make Outlook(tm) understand your answers to invitation replies" ) );
04939   QWhatsThis::add( mLegacyMangleFromTo, i18n( GlobalSettings::self()->
04940            legacyMangleFromToHeadersItem()->whatsThis().utf8() ) );
04941   connect( mLegacyMangleFromTo, SIGNAL( stateChanged( int ) ),
04942            this, SLOT( slotEmitChanged( void ) ) );
04943   mLegacyBodyInvites = new QCheckBox( i18n( "Send invitations in the mail body" ), gBox );
04944   QToolTip::add( mLegacyBodyInvites, i18n( "Turn this option on in order to make Outlook(tm) understand your answers to invitations" ) );
04945   QWhatsThis::add( mLegacyMangleFromTo, i18n( GlobalSettings::self()->
04946            legacyBodyInvitesItem()->whatsThis().utf8() ) );
04947   connect( mLegacyBodyInvites, SIGNAL( toggled( bool ) ),
04948            this, SLOT( slotLegacyBodyInvitesToggled( bool ) ) );
04949   connect( mLegacyBodyInvites, SIGNAL( stateChanged( int ) ),
04950            this, SLOT( slotEmitChanged( void ) ) );
04951 
04952   mExchangeCompatibleInvitations = new QCheckBox( i18n( "Exchange compatible invitation naming" ), gBox );
04953   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." ) );
04954   QWhatsThis::add( mExchangeCompatibleInvitations, i18n( GlobalSettings::self()->
04955            exchangeCompatibleInvitationsItem()->whatsThis().utf8() ) );
04956   connect( mExchangeCompatibleInvitations, SIGNAL( stateChanged( int ) ),
04957            this, SLOT( slotEmitChanged( void ) ) );
04958 
04959   mOutlookCompatibleInvitationComments = new QCheckBox( i18n( "Outlook compatible invitation reply comments" ), gBox );
04960   QToolTip::add( mOutlookCompatibleInvitationComments, i18n( "Send invitation reply comments in a way that Microsoft Outlook(tm) understands." ) );
04961   QWhatsThis::add( mOutlookCompatibleInvitationComments, i18n( GlobalSettings::self()->
04962            outlookCompatibleInvitationReplyCommentsItem()->whatsThis().utf8() ) );
04963   connect( mOutlookCompatibleInvitationComments, SIGNAL( stateChanged( int ) ),
04964            this, SLOT( slotEmitChanged( void ) ) );
04965 
04966   mOutlookCompatibleInvitationComparisons =
04967     new QCheckBox( i18n( "Show invitation update differences in the Outlook style" ), gBox );
04968   QToolTip::add( mOutlookCompatibleInvitationComparisons,
04969                  i18n( "Display invitation update differences in the Microsoft Outlook(tm) style." ) );
04970   QWhatsThis::add( mOutlookCompatibleInvitationComparisons,
04971                    i18n( GlobalSettings::self()->
04972                          outlookCompatibleInvitationComparisonsItem()->whatsThis().utf8() ) );
04973   connect( mOutlookCompatibleInvitationComparisons, SIGNAL( stateChanged( int ) ),
04974            this, SLOT( slotEmitChanged( void ) ) );
04975 
04976   mAutomaticSending = new QCheckBox( i18n( "Automatic invitation sending" ), gBox );
04977   QToolTip::add( mAutomaticSending, i18n( "When this is on, the user will not see the mail composer window. Invitation mails are sent automatically" ) );
04978   QWhatsThis::add( mAutomaticSending, i18n( GlobalSettings::self()->
04979            automaticSendingItem()->whatsThis().utf8() ) );
04980   connect( mAutomaticSending, SIGNAL( stateChanged( int ) ),
04981            this, SLOT( slotEmitChanged( void ) ) );
04982 
04983   // Open space padding at the end
04984   new QLabel( this );
04985 }
04986 
04987 void MiscPageGroupwareTab::slotLegacyBodyInvitesToggled( bool on )
04988 {
04989   if ( on ) {
04990     QString txt = i18n( "<qt>Invitations are normally sent as attachments to "
04991                         "a mail. This switch changes the invitation mails to "
04992                         "be sent in the text of the mail instead; this is "
04993                         "necessary to send invitations and replies to "
04994                         "Microsoft Outlook.<br>But, when you do this, you no "
04995                         "longer get descriptive text that mail programs "
04996                         "can read; so, to people who have email programs "
04997                         "that do not understand the invitations, the "
04998                         "resulting messages look very odd.<br>People that have email "
04999                         "programs that do understand invitations will still "
05000                         "be able to work with this.</qt>" );
05001     KMessageBox::information( this, txt, QString::null,
05002                               "LegacyBodyInvitesWarning" );
05003   }
05004   // Invitations in the body are autosent in any case (no point in editing raw ICAL)
05005   // So the autosend option is only available if invitations are sent as attachment.
05006   mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() );
05007 }
05008 
05009 void MiscPage::GroupwareTab::doLoadFromGlobalSettings() {
05010   if ( mEnableGwCB ) {
05011     mEnableGwCB->setChecked( GlobalSettings::self()->groupwareEnabled() );
05012     gBox->setEnabled( mEnableGwCB->isChecked() );
05013   }
05014 
05015   mLegacyMangleFromTo->setChecked( GlobalSettings::self()->legacyMangleFromToHeaders() );
05016   mLegacyBodyInvites->blockSignals( true );
05017 
05018   mLegacyBodyInvites->setChecked( GlobalSettings::self()->legacyBodyInvites() );
05019   mLegacyBodyInvites->blockSignals( false );
05020 
05021   mExchangeCompatibleInvitations->setChecked( GlobalSettings::self()->exchangeCompatibleInvitations() );
05022 
05023   mOutlookCompatibleInvitationComments->setChecked( GlobalSettings::self()->outlookCompatibleInvitationReplyComments() );
05024   mOutlookCompatibleInvitationComparisons->setChecked( GlobalSettings::self()->outlookCompatibleInvitationComparisons() );
05025 
05026   mAutomaticSending->setChecked( GlobalSettings::self()->automaticSending() );
05027   mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() );
05028 
05029   // Read the IMAP resource config
05030   mEnableImapResCB->setChecked( GlobalSettings::self()->theIMAPResourceEnabled() );
05031   mBox->setEnabled( mEnableImapResCB->isChecked() );
05032 
05033   mHideGroupwareFolders->setChecked( GlobalSettings::self()->hideGroupwareFolders() );
05034   int i = GlobalSettings::self()->theIMAPResourceFolderLanguage();
05035   mLanguageCombo->setCurrentItem(i);
05036   i = GlobalSettings::self()->theIMAPResourceStorageFormat();
05037   mStorageFormatCombo->setCurrentItem(i);
05038   slotStorageFormatChanged( i );
05039   mOnlyShowGroupwareFolders->setChecked( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount() );
05040   mSyncImmediately->setChecked( GlobalSettings::self()->immediatlySyncDIMAPOnGroupwareChanges() );
05041   mDeleteInvitations->setChecked( GlobalSettings::self()->deleteInvitationEmailsAfterSendingReply() );
05042 
05043   QString folderId( GlobalSettings::self()->theIMAPResourceFolderParent() );
05044   if( !folderId.isNull() && kmkernel->findFolderById( folderId ) ) {
05045     mFolderCombo->setFolder( folderId );
05046   } else {
05047     // Folder was deleted, we have to choose a new one
05048     mFolderCombo->setFolder( i18n( "<Choose a Folder>" ) );
05049   }
05050 
05051   KMAccount* selectedAccount = 0;
05052   int accountId = GlobalSettings::self()->theIMAPResourceAccount();
05053   if ( accountId )
05054     selectedAccount = kmkernel->acctMgr()->find( accountId );
05055   else {
05056     // Fallback: iterate over accounts to select folderId if found (as an inbox folder)
05057       for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0;
05058          a = kmkernel->acctMgr()->next() ) {
05059       if( a->folder() && a->folder()->child() ) {
05060         // Look inside that folder for an INBOX
05061         KMFolderNode *node;
05062         for (node = a->folder()->child()->first(); node; node = a->folder()->child()->next())
05063           if (!node->isDir() && node->name() == "INBOX") break;
05064 
05065         if ( node && static_cast<KMFolder*>(node)->idString() == folderId ) {
05066           selectedAccount = a;
05067           break;
05068         }
05069       }
05070     }
05071   }
05072   if ( selectedAccount )
05073     mAccountCombo->setCurrentAccount( selectedAccount );
05074   else if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == 1 )
05075     kdDebug(5006) << "Folder " << folderId << " not found as an account's inbox" << endl;
05076 }
05077 
05078 void MiscPage::GroupwareTab::save() {
05079   KConfigGroup groupware( KMKernel::config(), "Groupware" );
05080 
05081   // Write the groupware config
05082   if ( mEnableGwCB ) {
05083     groupware.writeEntry( "GroupwareEnabled", mEnableGwCB->isChecked() );
05084   }
05085   groupware.writeEntry( "LegacyMangleFromToHeaders", mLegacyMangleFromTo->isChecked() );
05086   groupware.writeEntry( "LegacyBodyInvites", mLegacyBodyInvites->isChecked() );
05087   groupware.writeEntry( "ExchangeCompatibleInvitations", mExchangeCompatibleInvitations->isChecked() );
05088   groupware.writeEntry( "OutlookCompatibleInvitationReplyComments", mOutlookCompatibleInvitationComments->isChecked() );
05089   groupware.writeEntry( "OutlookCompatibleInvitationComparisons", mOutlookCompatibleInvitationComparisons->isChecked() );
05090   groupware.writeEntry( "AutomaticSending", mAutomaticSending->isChecked() );
05091 
05092   if ( mEnableGwCB ) {
05093     GlobalSettings::self()->setGroupwareEnabled( mEnableGwCB->isChecked() );
05094   }
05095   GlobalSettings::self()->setLegacyMangleFromToHeaders( mLegacyMangleFromTo->isChecked() );
05096   GlobalSettings::self()->setLegacyBodyInvites( mLegacyBodyInvites->isChecked() );
05097   GlobalSettings::self()->setExchangeCompatibleInvitations( mExchangeCompatibleInvitations->isChecked() );
05098   GlobalSettings::self()->setOutlookCompatibleInvitationReplyComments( mOutlookCompatibleInvitationComments->isChecked() );
05099   GlobalSettings::self()->setOutlookCompatibleInvitationComparisons( mOutlookCompatibleInvitationComparisons->isChecked() );
05100   GlobalSettings::self()->setAutomaticSending( mAutomaticSending->isChecked() );
05101 
05102   int format = mStorageFormatCombo->currentItem();
05103   GlobalSettings::self()->setTheIMAPResourceStorageFormat( format );
05104 
05105   // Write the IMAP resource config
05106   GlobalSettings::self()->setHideGroupwareFolders( mHideGroupwareFolders->isChecked() );
05107   GlobalSettings::self()->setShowOnlyGroupwareFoldersForGroupwareAccount( mOnlyShowGroupwareFolders->isChecked() );
05108   GlobalSettings::self()->setImmediatlySyncDIMAPOnGroupwareChanges( mSyncImmediately->isChecked() );
05109   GlobalSettings::self()->setDeleteInvitationEmailsAfterSendingReply( mDeleteInvitations->isChecked() );
05110 
05111   // If there is a leftover folder in the foldercombo, getFolder can
05112   // return 0. In that case we really don't have it enabled
05113   QString folderId;
05114   if (  format == 0 ) {
05115     KMFolder* folder = mFolderCombo->folder();
05116     if (  folder )
05117       folderId = folder->idString();
05118     KMAccount* account = 0;
05119     // Didn't find an easy way to find the account for a given folder...
05120     // Fallback: iterate over accounts to select folderId if found (as an inbox folder)
05121     for( KMAccount *a = kmkernel->acctMgr()->first();
05122         a && !account; // stop when found
05123         a = kmkernel->acctMgr()->next() ) {
05124       if( a->folder() && a->folder()->child() ) {
05125         KMFolderNode *node;
05126         for ( node = a->folder()->child()->first(); node; node = a->folder()->child()->next() )
05127         {
05128           if ( static_cast<KMFolder*>(node) == folder ) {
05129             account = a;
05130             break;
05131           }
05132         }
05133       }
05134     }
05135     GlobalSettings::self()->setTheIMAPResourceAccount( account ? account->id() : 0 );
05136   } else {
05137     // Inbox folder of the selected account
05138     KMAccount* acct = mAccountCombo->currentAccount();
05139     if (  acct ) {
05140       folderId = QString( ".%1.directory/INBOX" ).arg( acct->id() );
05141       GlobalSettings::self()->setTheIMAPResourceAccount( acct->id() );
05142     }
05143   }
05144 
05145   bool enabled = mEnableImapResCB->isChecked() && !folderId.isEmpty();
05146   GlobalSettings::self()->setTheIMAPResourceEnabled( enabled );
05147   GlobalSettings::self()->setTheIMAPResourceFolderLanguage( mLanguageCombo->currentItem() );
05148   GlobalSettings::self()->setTheIMAPResourceFolderParent( folderId );
05149 }
05150 
05151 void MiscPage::GroupwareTab::slotStorageFormatChanged( int format )
05152 {
05153   mLanguageCombo->setEnabled( format == 0 ); // only ical/vcard needs the language hack
05154   mFolderComboStack->raiseWidget( format );
05155   if ( format == 0 ) {
05156     mFolderComboLabel->setText( i18n("&Resource folders are subfolders of:") );
05157     mFolderComboLabel->setBuddy( mFolderCombo );
05158   } else {
05159     mFolderComboLabel->setText( i18n("&Resource folders are in account:") );
05160     mFolderComboLabel->setBuddy( mAccountCombo );
05161   }
05162   slotEmitChanged();
05163 }
05164 
05165 
05166 // *************************************************************
05167 // *                                                           *
05168 // *                     AccountUpdater                        *
05169 // *                                                           *
05170 // *************************************************************
05171 AccountUpdater::AccountUpdater(ImapAccountBase *account)
05172     : QObject()
05173 {
05174   mAccount = account;
05175 }
05176 
05177 void AccountUpdater::update()
05178 {
05179   connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
05180           this, SLOT( namespacesFetched() ) );
05181   mAccount->makeConnection();
05182 }
05183 
05184 void AccountUpdater::namespacesFetched()
05185 {
05186   mAccount->setCheckingMail( true );
05187   mAccount->processNewMail( false );
05188   deleteLater();
05189 }
05190 
05191 #undef DIM
05192 
05193 //----------------------------
05194 #include "configuredialog.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys