kmail Library API Documentation

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