kmail

configuredialog.cpp

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