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   { "CloseToQuotaColor", I18N_NOOP("Folder Name and Size When Close to Quota") },
01729   { "ColorbarBackgroundPlain", I18N_NOOP("HTML Status Bar Background - No HTML Message") },
01730   { "ColorbarForegroundPlain", I18N_NOOP("HTML Status Bar Foreground - No HTML Message") },
01731   { "ColorbarBackgroundHTML",  I18N_NOOP("HTML Status Bar Background - HTML Message") },
01732   { "ColorbarForegroundHTML",  I18N_NOOP("HTML Status Bar Foreground - HTML Message") },
01733 };
01734 static const int numColorNames = sizeof colorNames / sizeof *colorNames;
01735 
01736 AppearancePageColorsTab::AppearancePageColorsTab( QWidget * parent, const char * name )
01737   : ConfigModuleTab( parent, name )
01738 {
01739   // tmp. vars:
01740   QVBoxLayout *vlay;
01741 
01742   // "use custom colors" check box
01743   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
01744   mCustomColorCheck = new QCheckBox( i18n("&Use custom colors"), this );
01745   vlay->addWidget( mCustomColorCheck );
01746   connect( mCustomColorCheck, SIGNAL( stateChanged( int ) ),
01747            this, SLOT( slotEmitChanged( void ) ) );
01748 
01749   // color list box:
01750   mColorList = new ColorListBox( this );
01751   mColorList->setEnabled( false ); // since !mCustomColorCheck->isChecked()
01752   QStringList modeList;
01753   for ( int i = 0 ; i < numColorNames ; i++ )
01754     mColorList->insertItem( new ColorListItem( i18n( colorNames[i].displayName ) ) );
01755   vlay->addWidget( mColorList, 1 );
01756 
01757   // "recycle colors" check box:
01758   mRecycleColorCheck =
01759     new QCheckBox( i18n("Recycle colors on deep &quoting"), this );
01760   mRecycleColorCheck->setEnabled( false );
01761   vlay->addWidget( mRecycleColorCheck );
01762   connect( mRecycleColorCheck, SIGNAL( stateChanged( int ) ),
01763            this, SLOT( slotEmitChanged( void ) ) );
01764 
01765   // close to quota threshold
01766   QHBoxLayout *hbox = new QHBoxLayout(vlay);
01767   QLabel *l = new QLabel( i18n("Close to quota threshold"), this );
01768   hbox->addWidget( l );
01769   l->setEnabled( false );
01770   mCloseToQuotaThreshold = new QSpinBox( 0, 100, 1, this );
01771   connect( mCloseToQuotaThreshold, SIGNAL( valueChanged( int ) ),
01772            this, SLOT( slotEmitChanged( void ) ) );
01773   mCloseToQuotaThreshold->setSuffix( i18n("%"));
01774   hbox->addWidget( mCloseToQuotaThreshold );
01775   hbox->addWidget( new QWidget(this), 2 );
01776 
01777   // {en,dir}able widgets depending on the state of mCustomColorCheck:
01778   connect( mCustomColorCheck, SIGNAL(toggled(bool)),
01779            mColorList, SLOT(setEnabled(bool)) );
01780   connect( mCustomColorCheck, SIGNAL(toggled(bool)),
01781            mRecycleColorCheck, SLOT(setEnabled(bool)) );
01782   connect( mCustomColorCheck, SIGNAL(toggled(bool)),
01783            l, SLOT(setEnabled(bool)) );
01784 
01785   connect( mCustomColorCheck, SIGNAL( stateChanged( int ) ),
01786            this, SLOT( slotEmitChanged( void ) ) );
01787 }
01788 
01789 void AppearancePage::ColorsTab::doLoadOther() {
01790   KConfigGroup reader( KMKernel::config(), "Reader" );
01791 
01792   mCustomColorCheck->setChecked( !reader.readBoolEntry( "defaultColors", true ) );
01793   mRecycleColorCheck->setChecked( reader.readBoolEntry( "RecycleQuoteColors", false ) );
01794   mCloseToQuotaThreshold->setValue( GlobalSettings::closeToQuotaThreshold() );
01795 
01796   static const QColor defaultColor[ numColorNames ] = {
01797     kapp->palette().active().base(), // bg
01798     KGlobalSettings::alternateBackgroundColor(), // alt bg
01799     kapp->palette().active().text(), // fg
01800     QColor( 0x00, 0x80, 0x00 ), // quoted l1
01801     QColor( 0x00, 0x70, 0x00 ), // quoted l2
01802     QColor( 0x00, 0x60, 0x00 ), // quoted l3
01803     KGlobalSettings::linkColor(), // link
01804     KGlobalSettings::visitedLinkColor(), // visited link
01805     Qt::red, // misspelled words
01806     Qt::red, // new msg
01807     Qt::blue, // unread mgs
01808     QColor( 0x00, 0x7F, 0x00 ), // important msg
01809     Qt::blue, // todo mgs
01810     QColor( 0x00, 0x80, 0xFF ), // light blue // pgp encrypted
01811     QColor( 0x40, 0xFF, 0x40 ), // light green // pgp ok, trusted key
01812     QColor( 0xFF, 0xFF, 0x40 ), // light yellow // pgp ok, untrusted key
01813     QColor( 0xFF, 0xFF, 0x40 ), // light yellow // pgp unchk
01814     Qt::red, // pgp bad
01815     QColor( 0xFF, 0x40, 0x40 ), // warning text color: light red
01816     Qt::red, // close to quota
01817     Qt::lightGray, // colorbar plain bg
01818     Qt::black,     // colorbar plain fg
01819     Qt::black,     // colorbar html  bg
01820     Qt::white,     // colorbar html  fg
01821   };
01822 
01823   for ( int i = 0 ; i < numColorNames ; i++ ) {
01824     mColorList->setColor( i,
01825       reader.readColorEntry( colorNames[i].configName, &defaultColor[i] ) );
01826   }
01827   connect( mColorList, SIGNAL( changed( ) ),
01828            this, SLOT( slotEmitChanged( void ) ) );
01829 }
01830 
01831 void AppearancePage::ColorsTab::installProfile( KConfig * profile ) {
01832   KConfigGroup reader( profile, "Reader" );
01833 
01834   if ( reader.hasKey( "defaultColors" ) )
01835     mCustomColorCheck->setChecked( !reader.readBoolEntry( "defaultColors" ) );
01836   if ( reader.hasKey( "RecycleQuoteColors" ) )
01837     mRecycleColorCheck->setChecked( reader.readBoolEntry( "RecycleQuoteColors" ) );
01838 
01839   for ( int i = 0 ; i < numColorNames ; i++ )
01840     if ( reader.hasKey( colorNames[i].configName ) )
01841       mColorList->setColor( i, reader.readColorEntry( colorNames[i].configName ) );
01842 }
01843 
01844 void AppearancePage::ColorsTab::save() {
01845   KConfigGroup reader( KMKernel::config(), "Reader" );
01846 
01847   bool customColors = mCustomColorCheck->isChecked();
01848   reader.writeEntry( "defaultColors", !customColors );
01849 
01850   for ( int i = 0 ; i < numColorNames ; i++ )
01851     // Don't write color info when we use default colors, but write
01852     // if it's already there:
01853     if ( customColors || reader.hasKey( colorNames[i].configName ) )
01854       reader.writeEntry( colorNames[i].configName, mColorList->color(i) );
01855 
01856   reader.writeEntry( "RecycleQuoteColors", mRecycleColorCheck->isChecked() );
01857   GlobalSettings::setCloseToQuotaThreshold( mCloseToQuotaThreshold->value() );
01858 }
01859 
01860 QString AppearancePage::LayoutTab::helpAnchor() const {
01861   return QString::fromLatin1("configure-appearance-layout");
01862 }
01863 
01864 static const EnumConfigEntryItem folderListModes[] = {
01865   { "long", I18N_NOOP("Lon&g folder list") },
01866   { "short", I18N_NOOP("Shor&t folder list" ) }
01867 };
01868 static const EnumConfigEntry folderListMode = {
01869   "Geometry", "FolderList", I18N_NOOP("Folder List"),
01870   folderListModes, DIM(folderListModes), 0
01871 };
01872 
01873 
01874 static const EnumConfigEntryItem mimeTreeLocations[] = {
01875   { "top", I18N_NOOP("Abo&ve the message pane") },
01876   { "bottom", I18N_NOOP("&Below the message pane") }
01877 };
01878 static const EnumConfigEntry mimeTreeLocation = {
01879   "Reader", "MimeTreeLocation", I18N_NOOP("Message Structure Viewer Placement"),
01880   mimeTreeLocations, DIM(mimeTreeLocations), 1
01881 };
01882 
01883 static const EnumConfigEntryItem mimeTreeModes[] = {
01884   { "never", I18N_NOOP("Show &never") },
01885   { "smart", I18N_NOOP("Show only for non-plaintext &messages") },
01886   { "always", I18N_NOOP("Show alway&s") }
01887 };
01888 static const EnumConfigEntry mimeTreeMode = {
01889   "Reader", "MimeTreeMode", I18N_NOOP("Message Structure Viewer"),
01890   mimeTreeModes, DIM(mimeTreeModes), 1
01891 };
01892 
01893 
01894 static const EnumConfigEntryItem readerWindowModes[] = {
01895   { "hide", I18N_NOOP("&Do not show a message preview pane") },
01896   { "below", I18N_NOOP("Show the message preview pane belo&w the message list") },
01897   { "right", I18N_NOOP("Show the message preview pane ne&xt to the message list") }
01898 };
01899 static const EnumConfigEntry readerWindowMode = {
01900   "Geometry", "readerWindowMode", I18N_NOOP("Message Preview Pane"),
01901   readerWindowModes, DIM(readerWindowModes), 1
01902 };
01903 
01904 AppearancePageLayoutTab::AppearancePageLayoutTab( QWidget * parent, const char * name )
01905   : ConfigModuleTab( parent, name )
01906 {
01907   // tmp. vars:
01908   QVBoxLayout * vlay;
01909 
01910   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
01911 
01912   // "folder list" radio buttons:
01913   populateButtonGroup( mFolderListGroup = new QHButtonGroup( this ), folderListMode );
01914   vlay->addWidget( mFolderListGroup );
01915   connect( mFolderListGroup, SIGNAL ( clicked( int ) ),
01916            this, SLOT( slotEmitChanged() ) );
01917 
01918   mFavoriteFolderViewCB = new QCheckBox( i18n("Show favorite folder view"), this );
01919   connect( mFavoriteFolderViewCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
01920   vlay->addWidget( mFavoriteFolderViewCB );
01921 
01922   // "show reader window" radio buttons:
01923   populateButtonGroup( mReaderWindowModeGroup = new QVButtonGroup( this ), readerWindowMode );
01924   vlay->addWidget( mReaderWindowModeGroup );
01925   connect( mReaderWindowModeGroup, SIGNAL ( clicked( int ) ),
01926            this, SLOT( slotEmitChanged() ) );
01927 
01928   // "Show MIME Tree" radio buttons:
01929   populateButtonGroup( mMIMETreeModeGroup = new QVButtonGroup( this ), mimeTreeMode );
01930   vlay->addWidget( mMIMETreeModeGroup );
01931   connect( mMIMETreeModeGroup, SIGNAL ( clicked( int ) ),
01932            this, SLOT( slotEmitChanged() ) );
01933 
01934   // "MIME Tree Location" radio buttons:
01935   populateButtonGroup( mMIMETreeLocationGroup = new QHButtonGroup( this ), mimeTreeLocation );
01936   vlay->addWidget( mMIMETreeLocationGroup );
01937   connect( mMIMETreeLocationGroup, SIGNAL ( clicked( int ) ),
01938            this, SLOT( slotEmitChanged() ) );
01939 
01940   vlay->addStretch( 10 ); // spacer
01941 }
01942 
01943 void AppearancePage::LayoutTab::doLoadOther() {
01944   const KConfigGroup reader( KMKernel::config(), "Reader" );
01945   const KConfigGroup geometry( KMKernel::config(), "Geometry" );
01946 
01947   loadWidget( mFolderListGroup, geometry, folderListMode );
01948   loadWidget( mMIMETreeLocationGroup, reader, mimeTreeLocation );
01949   loadWidget( mMIMETreeModeGroup, reader, mimeTreeMode );
01950   loadWidget( mReaderWindowModeGroup, geometry, readerWindowMode );
01951   mFavoriteFolderViewCB->setChecked( GlobalSettings::self()->enableFavoriteFolderView() );
01952 }
01953 
01954 void AppearancePage::LayoutTab::installProfile( KConfig * profile ) {
01955   const KConfigGroup reader( profile, "Reader" );
01956   const KConfigGroup geometry( profile, "Geometry" );
01957 
01958   loadProfile( mFolderListGroup, geometry, folderListMode );
01959   loadProfile( mMIMETreeLocationGroup, reader, mimeTreeLocation );
01960   loadProfile( mMIMETreeModeGroup, reader, mimeTreeMode );
01961   loadProfile( mReaderWindowModeGroup, geometry, readerWindowMode );
01962 }
01963 
01964 void AppearancePage::LayoutTab::save() {
01965   KConfigGroup reader( KMKernel::config(), "Reader" );
01966   KConfigGroup geometry( KMKernel::config(), "Geometry" );
01967 
01968   saveButtonGroup( mFolderListGroup, geometry, folderListMode );
01969   saveButtonGroup( mMIMETreeLocationGroup, reader, mimeTreeLocation );
01970   saveButtonGroup( mMIMETreeModeGroup, reader, mimeTreeMode );
01971   saveButtonGroup( mReaderWindowModeGroup, geometry, readerWindowMode );
01972   GlobalSettings::self()->setEnableFavoriteFolderView( mFavoriteFolderViewCB->isChecked() );
01973 }
01974 
01975 //
01976 // Appearance Message List
01977 //
01978 
01979 QString AppearancePage::HeadersTab::helpAnchor() const {
01980   return QString::fromLatin1("configure-appearance-headers");
01981 }
01982 
01983 static const struct {
01984   const char * displayName;
01985   DateFormatter::FormatType dateDisplay;
01986 } dateDisplayConfig[] = {
01987   { I18N_NOOP("Sta&ndard format (%1)"), KMime::DateFormatter::CTime },
01988   { I18N_NOOP("Locali&zed format (%1)"), KMime::DateFormatter::Localized },
01989   { I18N_NOOP("Fancy for&mat (%1)"), KMime::DateFormatter::Fancy },
01990   { I18N_NOOP("C&ustom format (Shift+F1 for help):"),
01991     KMime::DateFormatter::Custom }
01992 };
01993 static const int numDateDisplayConfig =
01994   sizeof dateDisplayConfig / sizeof *dateDisplayConfig;
01995 
01996 AppearancePageHeadersTab::AppearancePageHeadersTab( QWidget * parent, const char * name )
01997   : ConfigModuleTab( parent, name ),
01998     mCustomDateFormatEdit( 0 )
01999 {
02000   // tmp. vars:
02001   QButtonGroup * group;
02002   QRadioButton * radio;
02003 
02004   QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
02005 
02006   // "General Options" group:
02007   group = new QVButtonGroup( i18n( "General Options" ), this );
02008   group->layout()->setSpacing( KDialog::spacingHint() );
02009 
02010   mMessageSizeCheck = new QCheckBox( i18n("Display messa&ge sizes"), group );
02011 
02012   mCryptoIconsCheck = new QCheckBox( i18n( "Show crypto &icons" ), group );
02013 
02014   mAttachmentCheck = new QCheckBox( i18n("Show attachment icon"), group );
02015 
02016   mNestedMessagesCheck =
02017     new QCheckBox( i18n("&Threaded message list"), group );
02018 
02019   connect( mMessageSizeCheck, SIGNAL( stateChanged( int ) ),
02020            this, SLOT( slotEmitChanged( void ) ) );
02021   connect( mAttachmentCheck, SIGNAL( stateChanged( int ) ),
02022            this, SLOT( slotEmitChanged( void ) ) );
02023   connect( mCryptoIconsCheck, SIGNAL( stateChanged( int ) ),
02024            this, SLOT( slotEmitChanged( void ) ) );
02025   connect( mNestedMessagesCheck, SIGNAL( stateChanged( int ) ),
02026            this, SLOT( slotEmitChanged( void ) ) );
02027 
02028 
02029   vlay->addWidget( group );
02030 
02031   // "Message Header Threading Options" group:
02032   mNestingPolicy =
02033     new QVButtonGroup( i18n("Threaded Message List Options"), this );
02034   mNestingPolicy->layout()->setSpacing( KDialog::spacingHint() );
02035 
02036   mNestingPolicy->insert(
02037     new QRadioButton( i18n("Always &keep threads open"),
02038                       mNestingPolicy ), 0 );
02039   mNestingPolicy->insert(
02040     new QRadioButton( i18n("Threads default to o&pen"),
02041                       mNestingPolicy ), 1 );
02042   mNestingPolicy->insert(
02043     new QRadioButton( i18n("Threads default to closed"),
02044                       mNestingPolicy ), 2 );
02045   mNestingPolicy->insert(
02046     new QRadioButton( i18n("Open threads that contain ne&w, unread "
02047                            "or important messages and open watched threads."),
02048                       mNestingPolicy ), 3 );
02049 
02050   vlay->addWidget( mNestingPolicy );
02051 
02052   connect( mNestingPolicy, SIGNAL( clicked( int ) ),
02053            this, SLOT( slotEmitChanged( void ) ) );
02054 
02055   // "Date Display" group:
02056   mDateDisplay = new QVButtonGroup( i18n("Date Display"), this );
02057   mDateDisplay->layout()->setSpacing( KDialog::spacingHint() );
02058 
02059   for ( int i = 0 ; i < numDateDisplayConfig ; i++ ) {
02060     QString buttonLabel = i18n(dateDisplayConfig[i].displayName);
02061     if ( buttonLabel.contains("%1") )
02062       buttonLabel = buttonLabel.arg( DateFormatter::formatCurrentDate( dateDisplayConfig[i].dateDisplay ) );
02063     radio = new QRadioButton( buttonLabel, mDateDisplay );
02064     mDateDisplay->insert( radio, i );
02065     if ( dateDisplayConfig[i].dateDisplay == DateFormatter::Custom ) {
02066       mCustomDateFormatEdit = new KLineEdit( mDateDisplay );
02067       mCustomDateFormatEdit->setEnabled( false );
02068       connect( radio, SIGNAL(toggled(bool)),
02069                mCustomDateFormatEdit, SLOT(setEnabled(bool)) );
02070       connect( mCustomDateFormatEdit, SIGNAL(textChanged(const QString&)),
02071                this, SLOT(slotEmitChanged(void)) );
02072       QString customDateWhatsThis =
02073         i18n("<qt><p><strong>These expressions may be used for the date:"
02074              "</strong></p>"
02075              "<ul>"
02076              "<li>d - the day as a number without a leading zero (1-31)</li>"
02077              "<li>dd - the day as a number with a leading zero (01-31)</li>"
02078              "<li>ddd - the abbreviated day name (Mon - Sun)</li>"
02079              "<li>dddd - the long day name (Monday - Sunday)</li>"
02080              "<li>M - the month as a number without a leading zero (1-12)</li>"
02081              "<li>MM - the month as a number with a leading zero (01-12)</li>"
02082              "<li>MMM - the abbreviated month name (Jan - Dec)</li>"
02083              "<li>MMMM - the long month name (January - December)</li>"
02084              "<li>yy - the year as a two digit number (00-99)</li>"
02085              "<li>yyyy - the year as a four digit number (0000-9999)</li>"
02086              "</ul>"
02087              "<p><strong>These expressions may be used for the time:"
02088              "</string></p> "
02089              "<ul>"
02090              "<li>h - the hour without a leading zero (0-23 or 1-12 if AM/PM display)</li>"
02091              "<li>hh - the hour with a leading zero (00-23 or 01-12 if AM/PM display)</li>"
02092              "<li>m - the minutes without a leading zero (0-59)</li>"
02093              "<li>mm - the minutes with a leading zero (00-59)</li>"
02094              "<li>s - the seconds without a leading zero (0-59)</li>"
02095              "<li>ss - the seconds with a leading zero (00-59)</li>"
02096              "<li>z - the milliseconds without leading zeroes (0-999)</li>"
02097              "<li>zzz - the milliseconds with leading zeroes (000-999)</li>"
02098              "<li>AP - switch to AM/PM display. AP will be replaced by either \"AM\" or \"PM\".</li>"
02099              "<li>ap - switch to AM/PM display. ap will be replaced by either \"am\" or \"pm\".</li>"
02100              "<li>Z - time zone in numeric form (-0500)</li>"
02101              "</ul>"
02102              "<p><strong>All other input characters will be ignored."
02103              "</strong></p></qt>");
02104       QWhatsThis::add( mCustomDateFormatEdit, customDateWhatsThis );
02105       QWhatsThis::add( radio, customDateWhatsThis );
02106     }
02107   } // end for loop populating mDateDisplay
02108 
02109   vlay->addWidget( mDateDisplay );
02110   connect( mDateDisplay, SIGNAL( clicked( int ) ),
02111            this, SLOT( slotEmitChanged( void ) ) );
02112 
02113 
02114   vlay->addStretch( 10 ); // spacer
02115 }
02116 
02117 void AppearancePage::HeadersTab::doLoadOther() {
02118   KConfigGroup general( KMKernel::config(), "General" );
02119   KConfigGroup geometry( KMKernel::config(), "Geometry" );
02120 
02121   // "General Options":
02122   mNestedMessagesCheck->setChecked( geometry.readBoolEntry( "nestedMessages", false ) );
02123   mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize", false ) );
02124   mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons", false ) );
02125   mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon", true ) );
02126 
02127   // "Message Header Threading Options":
02128   int num = geometry.readNumEntry( "nestingPolicy", 3 );
02129   if ( num < 0 || num > 3 ) num = 3;
02130   mNestingPolicy->setButton( num );
02131 
02132   // "Date Display":
02133   setDateDisplay( general.readNumEntry( "dateFormat", DateFormatter::Fancy ),
02134                   general.readEntry( "customDateFormat" ) );
02135 }
02136 
02137 void AppearancePage::HeadersTab::setDateDisplay( int num, const QString & format ) {
02138   DateFormatter::FormatType dateDisplay =
02139     static_cast<DateFormatter::FormatType>( num );
02140 
02141   // special case: needs text for the line edit:
02142   if ( dateDisplay == DateFormatter::Custom )
02143     mCustomDateFormatEdit->setText( format );
02144 
02145   for ( int i = 0 ; i < numDateDisplayConfig ; i++ )
02146     if ( dateDisplay == dateDisplayConfig[i].dateDisplay ) {
02147       mDateDisplay->setButton( i );
02148       return;
02149     }
02150   // fell through since none found:
02151   mDateDisplay->setButton( numDateDisplayConfig - 2 ); // default
02152 }
02153 
02154 void AppearancePage::HeadersTab::installProfile( KConfig * profile ) {
02155   KConfigGroup general( profile, "General" );
02156   KConfigGroup geometry( profile, "Geometry" );
02157 
02158   if ( geometry.hasKey( "nestedMessages" ) )
02159     mNestedMessagesCheck->setChecked( geometry.readBoolEntry( "nestedMessages" ) );
02160   if ( general.hasKey( "showMessageSize" ) )
02161     mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize" ) );
02162 
02163   if( general.hasKey( "showCryptoIcons" ) )
02164     mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons" ) );
02165   if ( general.hasKey( "showAttachmentIcon" ) )
02166     mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon" ) );
02167 
02168   if ( geometry.hasKey( "nestingPolicy" ) ) {
02169     int num = geometry.readNumEntry( "nestingPolicy" );
02170     if ( num < 0 || num > 3 ) num = 3;
02171     mNestingPolicy->setButton( num );
02172   }
02173 
02174   if ( general.hasKey( "dateFormat" ) )
02175     setDateDisplay( general.readNumEntry( "dateFormat" ),
02176                    general.readEntry( "customDateFormat" ) );
02177 }
02178 
02179 void AppearancePage::HeadersTab::save() {
02180   KConfigGroup general( KMKernel::config(), "General" );
02181   KConfigGroup geometry( KMKernel::config(), "Geometry" );
02182 
02183   if ( geometry.readBoolEntry( "nestedMessages", false )
02184        != mNestedMessagesCheck->isChecked() ) {
02185     int result = KMessageBox::warningContinueCancel( this,
02186                    i18n("Changing the global threading setting will override "
02187                         "all folder specific values."),
02188                    QString::null, KStdGuiItem::cont(), "threadOverride" );
02189     if ( result == KMessageBox::Continue ) {
02190       geometry.writeEntry( "nestedMessages", mNestedMessagesCheck->isChecked() );
02191       // remove all threadMessagesOverride keys from all [Folder-*] groups:
02192       QStringList groups = KMKernel::config()->groupList().grep( QRegExp("^Folder-") );
02193       kdDebug(5006) << "groups.count() == " << groups.count() << endl;
02194       for ( QStringList::const_iterator it = groups.begin() ; it != groups.end() ; ++it ) {
02195         KConfigGroup group( KMKernel::config(), *it );
02196         group.deleteEntry( "threadMessagesOverride" );
02197       }
02198     }
02199   }
02200 
02201   geometry.writeEntry( "nestingPolicy",
02202                        mNestingPolicy->id( mNestingPolicy->selected() ) );
02203   general.writeEntry( "showMessageSize", mMessageSizeCheck->isChecked() );
02204   general.writeEntry( "showCryptoIcons", mCryptoIconsCheck->isChecked() );
02205   general.writeEntry( "showAttachmentIcon", mAttachmentCheck->isChecked() );
02206 
02207   int dateDisplayID = mDateDisplay->id( mDateDisplay->selected() );
02208   // check bounds:
02209   assert( dateDisplayID >= 0 ); assert( dateDisplayID < numDateDisplayConfig );
02210   general.writeEntry( "dateFormat",
02211                       dateDisplayConfig[ dateDisplayID ].dateDisplay );
02212   general.writeEntry( "customDateFormat", mCustomDateFormatEdit->text() );
02213 }
02214 
02215 
02216 //
02217 // Message Window
02218 //
02219 
02220 
02221 static const BoolConfigEntry showColorbarMode = {
02222   "Reader", "showColorbar", I18N_NOOP("Show HTML stat&us bar"), false
02223 };
02224 
02225 static const BoolConfigEntry showSpamStatusMode = {
02226   "Reader", "showSpamStatus", I18N_NOOP("Show s&pam status in fancy headers"), true
02227 };
02228 
02229 static const BoolConfigEntry showEmoticons = {
02230   "Reader", "ShowEmoticons", I18N_NOOP("Replace smileys by emoticons"), true
02231 };
02232 
02233 static const BoolConfigEntry shrinkQuotes = {
02234   "Reader", "ShrinkQuotes", I18N_NOOP("Use smaller font for quoted text"), false
02235 };
02236 
02237 static const BoolConfigEntry showExpandQuotesMark= {
02238   "Reader", "ShowExpandQuotesMark", I18N_NOOP("Show expand/collapse quote marks"), false
02239 };
02240 
02241 
02242 QString AppearancePage::ReaderTab::helpAnchor() const {
02243   return QString::fromLatin1("configure-appearance-reader");
02244 }
02245 
02246 AppearancePageReaderTab::AppearancePageReaderTab( QWidget * parent,
02247                                                   const char * name )
02248   : ConfigModuleTab( parent, name )
02249 {
02250   QVBoxLayout *vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
02251 
02252   // "show colorbar" check box:
02253   populateCheckBox( mShowColorbarCheck = new QCheckBox( this ), showColorbarMode );
02254   vlay->addWidget( mShowColorbarCheck );
02255   connect( mShowColorbarCheck, SIGNAL ( stateChanged( int ) ),
02256            this, SLOT( slotEmitChanged() ) );
02257 
02258   // "show spam status" check box;
02259   populateCheckBox( mShowSpamStatusCheck = new QCheckBox( this ), showSpamStatusMode );
02260   vlay->addWidget( mShowSpamStatusCheck );
02261   connect( mShowSpamStatusCheck, SIGNAL ( stateChanged( int ) ),
02262            this, SLOT( slotEmitChanged() ) );
02263 
02264   // "replace smileys by emoticons" check box;
02265   populateCheckBox( mShowEmoticonsCheck = new QCheckBox( this ), showEmoticons );
02266   vlay->addWidget( mShowEmoticonsCheck );
02267   connect( mShowEmoticonsCheck, SIGNAL ( stateChanged( int ) ),
02268            this, SLOT( slotEmitChanged() ) );
02269 
02270   // "Use smaller font for quoted text" check box
02271   mShrinkQuotesCheck = new QCheckBox( i18n( shrinkQuotes.desc ), this,
02272                                       "kcfg_ShrinkQuotes" );
02273   vlay->addWidget( mShrinkQuotesCheck );
02274   connect( mShrinkQuotesCheck, SIGNAL( stateChanged( int ) ),
02275            this, SLOT( slotEmitChanged() ) );
02276 
02277   // "Show expand/collaps quote marks" check box;
02278   QHBoxLayout *hlay= new QHBoxLayout( vlay ); // inherits spacing
02279   populateCheckBox( mShowExpandQuotesMark= new QCheckBox( this ), showExpandQuotesMark);
02280   hlay->addWidget( mShowExpandQuotesMark);
02281   connect( mShowExpandQuotesMark, SIGNAL ( stateChanged( int ) ),
02282            this, SLOT( slotEmitChanged() ) );
02283 
02284   hlay->addStretch( 1 );
02285   mCollapseQuoteLevelSpin = new KIntSpinBox( 0/*min*/,10/*max*/,1/*step*/,
02286       3/*init*/,10/*base*/,this );
02287 
02288   QLabel *label = new QLabel( mCollapseQuoteLevelSpin,
02289            GlobalSettings::self()->collapseQuoteLevelSpinItem()->label(), this );
02290 
02291   hlay->addWidget( label );
02292 
02293   mCollapseQuoteLevelSpin->setEnabled( false ); //since !mShowExpandQuotesMark->isCheckec()
02294   connect(  mCollapseQuoteLevelSpin, SIGNAL( valueChanged( int ) ),
02295       this, SLOT( slotEmitChanged( void ) ) );
02296   hlay->addWidget( mCollapseQuoteLevelSpin);
02297 
02298   connect( mShowExpandQuotesMark, SIGNAL( toggled( bool ) ),
02299       mCollapseQuoteLevelSpin, SLOT( setEnabled( bool ) ) );
02300 
02301   // Fallback Character Encoding
02302   hlay = new QHBoxLayout( vlay ); // inherits spacing
02303   mCharsetCombo = new QComboBox( this );
02304   mCharsetCombo->insertStringList( KMMsgBase::supportedEncodings( false ) );
02305 
02306   connect( mCharsetCombo, SIGNAL( activated( int ) ),
02307            this, SLOT( slotEmitChanged( void ) ) );
02308 
02309   QString fallbackCharsetWhatsThis =
02310     i18n( GlobalSettings::self()->fallbackCharacterEncodingItem()->whatsThis().utf8() );
02311   QWhatsThis::add( mCharsetCombo, fallbackCharsetWhatsThis );
02312 
02313   label = new QLabel( i18n("Fallback ch&aracter encoding:"), this );
02314   label->setBuddy( mCharsetCombo );
02315 
02316   hlay->addWidget( label );
02317   hlay->addWidget( mCharsetCombo );
02318 
02319   // Override Character Encoding
02320   QHBoxLayout *hlay2 = new QHBoxLayout( vlay ); // inherits spacing
02321   mOverrideCharsetCombo = new QComboBox( this );
02322   QStringList encodings = KMMsgBase::supportedEncodings( false );
02323   encodings.prepend( i18n( "Auto" ) );
02324   mOverrideCharsetCombo->insertStringList( encodings );
02325   mOverrideCharsetCombo->setCurrentItem(0);
02326 
02327   connect( mOverrideCharsetCombo, SIGNAL( activated( int ) ),
02328            this, SLOT( slotEmitChanged( void ) ) );
02329 
02330   QString overrideCharsetWhatsThis =
02331     i18n( GlobalSettings::self()->overrideCharacterEncodingItem()->whatsThis().utf8() );
02332   QWhatsThis::add( mOverrideCharsetCombo, overrideCharsetWhatsThis );
02333 
02334   label = new QLabel( i18n("&Override character encoding:"), this );
02335   label->setBuddy( mOverrideCharsetCombo );
02336 
02337   hlay2->addWidget( label );
02338   hlay2->addWidget( mOverrideCharsetCombo );
02339 
02340   vlay->addStretch( 100 ); // spacer
02341 }
02342 
02343 
02344 void AppearancePage::ReaderTab::readCurrentFallbackCodec()
02345 {
02346   QStringList encodings = KMMsgBase::supportedEncodings( false );
02347   QStringList::ConstIterator it( encodings.begin() );
02348   QStringList::ConstIterator end( encodings.end() );
02349   QString currentEncoding = GlobalSettings::self()->fallbackCharacterEncoding();
02350   currentEncoding = currentEncoding.replace( "iso ", "iso-", false );
02352   int i = 0;
02353   int indexOfLatin9 = 0;
02354   bool found = false;
02355   for( ; it != end; ++it)
02356   {
02357     const QString encoding = KGlobal::charsets()->encodingForName(*it);
02358     if ( encoding == "iso-8859-15" )
02359         indexOfLatin9 = i;
02360     if( encoding == currentEncoding )
02361     {
02362       mCharsetCombo->setCurrentItem( i );
02363       found = true;
02364       break;
02365     }
02366     i++;
02367   }
02368   if ( !found ) // nothing matched, use latin9
02369     mCharsetCombo->setCurrentItem( indexOfLatin9 );
02370 }
02371 
02372 void AppearancePage::ReaderTab::readCurrentOverrideCodec()
02373 {
02374   const QString &currentOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding();
02375   if ( currentOverrideEncoding.isEmpty() ) {
02376     mOverrideCharsetCombo->setCurrentItem( 0 );
02377     return;
02378   }
02379   QStringList encodings = KMMsgBase::supportedEncodings( false );
02380   encodings.prepend( i18n( "Auto" ) );
02381   QStringList::Iterator it( encodings.begin() );
02382   QStringList::Iterator end( encodings.end() );
02383   uint i = 0;
02384   for( ; it != end; ++it)
02385   {
02386     if( KGlobal::charsets()->encodingForName(*it) == currentOverrideEncoding )
02387     {
02388       mOverrideCharsetCombo->setCurrentItem( i );
02389       break;
02390     }
02391     i++;
02392   }
02393   if ( i == encodings.size() ) {
02394     // the current value of overrideCharacterEncoding is an unknown encoding => reset to Auto
02395     kdWarning(5006) << "Unknown override character encoding \"" << currentOverrideEncoding
02396                     << "\". Resetting to Auto." << endl;
02397     mOverrideCharsetCombo->setCurrentItem( 0 );
02398     GlobalSettings::self()->setOverrideCharacterEncoding( QString::null );
02399   }
02400 }
02401 
02402 void AppearancePage::ReaderTab::doLoadFromGlobalSettings()
02403 {
02404   mShowEmoticonsCheck->setChecked( GlobalSettings::self()->showEmoticons() );
02405   mShrinkQuotesCheck->setChecked( GlobalSettings::self()->shrinkQuotes() );
02406   mShowExpandQuotesMark->setChecked( GlobalSettings::self()->showExpandQuotesMark() );
02407   mCollapseQuoteLevelSpin->setValue( GlobalSettings::self()->collapseQuoteLevelSpin() );
02408   readCurrentFallbackCodec();
02409   readCurrentOverrideCodec();
02410 }
02411 
02412 void AppearancePage::ReaderTab::doLoadOther()
02413 {
02414   const KConfigGroup reader( KMKernel::config(), "Reader" );
02415   loadWidget( mShowColorbarCheck, reader, showColorbarMode );
02416   loadWidget( mShowSpamStatusCheck, reader, showSpamStatusMode );
02417 }
02418 
02419 
02420 void AppearancePage::ReaderTab::save() {
02421   KConfigGroup reader( KMKernel::config(), "Reader" );
02422   saveCheckBox( mShowColorbarCheck, reader, showColorbarMode );
02423   saveCheckBox( mShowSpamStatusCheck, reader, showSpamStatusMode );
02424   GlobalSettings::self()->setShowEmoticons( mShowEmoticonsCheck->isChecked() );
02425   GlobalSettings::self()->setShrinkQuotes( mShrinkQuotesCheck->isChecked() );
02426   GlobalSettings::self()->setShowExpandQuotesMark( mShowExpandQuotesMark->isChecked() );
02427 
02428   GlobalSettings::self()->setCollapseQuoteLevelSpin( mCollapseQuoteLevelSpin->value() );
02429   GlobalSettings::self()->setFallbackCharacterEncoding(
02430       KGlobal::charsets()->encodingForName( mCharsetCombo->currentText() ) );
02431   GlobalSettings::self()->setOverrideCharacterEncoding(
02432       mOverrideCharsetCombo->currentItem() == 0 ?
02433         QString() :
02434         KGlobal::charsets()->encodingForName( mOverrideCharsetCombo->currentText() ) );
02435 }
02436 
02437 
02438 void AppearancePage::ReaderTab::installProfile( KConfig * /* profile */ ) {
02439   const KConfigGroup reader( KMKernel::config(), "Reader" );
02440   loadProfile( mShowColorbarCheck, reader, showColorbarMode );
02441   loadProfile( mShowSpamStatusCheck, reader, showSpamStatusMode );
02442   loadProfile( mShowEmoticonsCheck, reader, showEmoticons );
02443   loadProfile( mShrinkQuotesCheck, reader, shrinkQuotes );
02444   loadProfile( mShowExpandQuotesMark, reader, showExpandQuotesMark);
02445 }
02446 
02447 
02448 QString AppearancePage::SystemTrayTab::helpAnchor() const {
02449   return QString::fromLatin1("configure-appearance-systemtray");
02450 }
02451 
02452 AppearancePageSystemTrayTab::AppearancePageSystemTrayTab( QWidget * parent,
02453                                                           const char * name )
02454   : ConfigModuleTab( parent, name )
02455 {
02456   QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(),
02457                                         KDialog::spacingHint() );
02458 
02459   // "Enable system tray applet" check box
02460   mSystemTrayCheck = new QCheckBox( i18n("Enable system tray icon"), this );
02461   vlay->addWidget( mSystemTrayCheck );
02462   connect( mSystemTrayCheck, SIGNAL( stateChanged( int ) ),
02463            this, SLOT( slotEmitChanged( void ) ) );
02464 
02465   // System tray modes
02466   mSystemTrayGroup = new QVButtonGroup( i18n("System Tray Mode"), this );
02467   mSystemTrayGroup->layout()->setSpacing( KDialog::spacingHint() );
02468   vlay->addWidget( mSystemTrayGroup );
02469   connect( mSystemTrayGroup, SIGNAL( clicked( int ) ),
02470            this, SLOT( slotEmitChanged( void ) ) );
02471   connect( mSystemTrayCheck, SIGNAL( toggled( bool ) ),
02472            mSystemTrayGroup, SLOT( setEnabled( bool ) ) );
02473 
02474   mSystemTrayGroup->insert( new QRadioButton( i18n("Always show KMail in system tray"), mSystemTrayGroup ),
02475                             GlobalSettings::EnumSystemTrayPolicy::ShowAlways );
02476 
02477   mSystemTrayGroup->insert( new QRadioButton( i18n("Only show KMail in system tray if there are unread messages"), mSystemTrayGroup ),
02478                             GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread );
02479 
02480   vlay->addStretch( 10 ); // spacer
02481 }
02482 
02483 void AppearancePage::SystemTrayTab::doLoadFromGlobalSettings() {
02484   mSystemTrayCheck->setChecked( GlobalSettings::self()->systemTrayEnabled() );
02485   mSystemTrayGroup->setButton( GlobalSettings::self()->systemTrayPolicy() );
02486   mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() );
02487 }
02488 
02489 void AppearancePage::SystemTrayTab::installProfile( KConfig * profile ) {
02490   KConfigGroup general( profile, "General" );
02491 
02492   if ( general.hasKey( "SystemTrayEnabled" ) ) {
02493     mSystemTrayCheck->setChecked( general.readBoolEntry( "SystemTrayEnabled" ) );
02494   }
02495   if ( general.hasKey( "SystemTrayPolicy" ) ) {
02496     mSystemTrayGroup->setButton( general.readNumEntry( "SystemTrayPolicy" ) );
02497   }
02498   mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() );
02499 }
02500 
02501 void AppearancePage::SystemTrayTab::save() {
02502   GlobalSettings::self()->setSystemTrayEnabled( mSystemTrayCheck->isChecked() );
02503   GlobalSettings::self()->setSystemTrayPolicy( mSystemTrayGroup->id( mSystemTrayGroup->selected() ) );
02504 }
02505 
02506 
02507 // *************************************************************
02508 // *                                                           *
02509 // *                      ComposerPage                         *
02510 // *                                                           *
02511 // *************************************************************
02512 
02513 QString ComposerPage::helpAnchor() const {
02514   return QString::fromLatin1("configure-composer");
02515 }
02516 
02517 ComposerPage::ComposerPage( QWidget * parent, const char * name )
02518   : ConfigModuleWithTabs( parent, name )
02519 {
02520   //
02521   // "General" tab:
02522   //
02523   mGeneralTab = new GeneralTab();
02524   addTab( mGeneralTab, i18n("&General") );
02525   addConfig( GlobalSettings::self(), mGeneralTab );
02526 
02527   //
02528   // "Phrases" tab:
02529   //
02530   // mPhrasesTab = new PhrasesTab();
02531   // addTab( mPhrasesTab, i18n("&Phrases") );
02532 
02533   //
02534   // "Templates" tab:
02535   //
02536   mTemplatesTab = new TemplatesTab();
02537   addTab( mTemplatesTab, i18n("&Templates") );
02538 
02539   //
02540   // "Custom Templates" tab:
02541   //
02542   mCustomTemplatesTab = new CustomTemplatesTab();
02543   addTab( mCustomTemplatesTab, i18n("&Custom Templates") );
02544 
02545   //
02546   // "Subject" tab:
02547   //
02548   mSubjectTab = new SubjectTab();
02549   addTab( mSubjectTab, i18n("&Subject") );
02550   addConfig( GlobalSettings::self(), mSubjectTab );
02551 
02552   //
02553   // "Charset" tab:
02554   //
02555   mCharsetTab = new CharsetTab();
02556   addTab( mCharsetTab, i18n("Cha&rset") );
02557 
02558   //
02559   // "Headers" tab:
02560   //
02561   mHeadersTab = new HeadersTab();
02562   addTab( mHeadersTab, i18n("H&eaders") );
02563 
02564   //
02565   // "Attachments" tab:
02566   //
02567   mAttachmentsTab = new AttachmentsTab();
02568   addTab( mAttachmentsTab, i18n("Config->Composer->Attachments", "A&ttachments") );
02569   load();
02570 }
02571 
02572 QString ComposerPage::GeneralTab::helpAnchor() const {
02573   return QString::fromLatin1("configure-composer-general");
02574 }
02575 
02576 ComposerPageGeneralTab::ComposerPageGeneralTab( QWidget * parent, const char * name )
02577   : ConfigModuleTab( parent, name )
02578 {
02579   // tmp. vars:
02580   QVBoxLayout *vlay;
02581   QHBoxLayout *hlay;
02582   QGroupBox   *group;
02583   QLabel      *label;
02584   QHBox       *hbox;
02585   QString      msg;
02586 
02587   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
02588 
02589   // some check buttons...
02590   mAutoAppSignFileCheck = new QCheckBox(
02591            GlobalSettings::self()->autoTextSignatureItem()->label(),
02592            this );
02593   vlay->addWidget( mAutoAppSignFileCheck );
02594   connect( mAutoAppSignFileCheck, SIGNAL( stateChanged(int) ),
02595            this, SLOT( slotEmitChanged( void ) ) );
02596 
02597   mTopQuoteCheck =
02598     new QCheckBox( GlobalSettings::self()->prependSignatureItem()->label(), this );
02599   vlay->addWidget( mTopQuoteCheck);
02600   connect( mTopQuoteCheck, SIGNAL( stateChanged(int) ),
02601            this, SLOT( slotEmitChanged( void ) ) );
02602 
02603   mSmartQuoteCheck = new QCheckBox(
02604            GlobalSettings::self()->smartQuoteItem()->label(),
02605            this, "kcfg_SmartQuote" );
02606   vlay->addWidget( mSmartQuoteCheck );
02607   connect( mSmartQuoteCheck, SIGNAL( stateChanged(int) ),
02608            this, SLOT( slotEmitChanged( void ) ) );
02609 
02610   mAutoRequestMDNCheck = new QCheckBox(
02611            GlobalSettings::self()->requestMDNItem()->label(),
02612            this, "kcfg_RequestMDN" );
02613   vlay->addWidget( mAutoRequestMDNCheck );
02614   connect( mAutoRequestMDNCheck, SIGNAL( stateChanged(int) ),
02615            this, SLOT( slotEmitChanged( void ) ) );
02616 
02617   mShowRecentAddressesInComposer = new QCheckBox(
02618            GlobalSettings::self()->showRecentAddressesInComposerItem()->label(),
02619            this, "kcfg_ShowRecentAddressesInComposer" );
02620   vlay->addWidget( mShowRecentAddressesInComposer );
02621   connect( mShowRecentAddressesInComposer, SIGNAL( stateChanged(int) ),
02622            this, SLOT( slotEmitChanged( void ) ) );
02623 
02624   // a checkbox for "word wrap" and a spinbox for the column in
02625   // which to wrap:
02626   hlay = new QHBoxLayout( vlay ); // inherits spacing
02627   mWordWrapCheck = new QCheckBox(
02628            GlobalSettings::self()->wordWrapItem()->label(),
02629            this, "kcfg_WordWrap" );
02630   hlay->addWidget( mWordWrapCheck );
02631   connect( mWordWrapCheck, SIGNAL( stateChanged(int) ),
02632            this, SLOT( slotEmitChanged( void ) ) );
02633 
02634   mWrapColumnSpin = new KIntSpinBox( 30/*min*/, 78/*max*/, 1/*step*/,
02635            78/*init*/, 10 /*base*/, this, "kcfg_LineWrapWidth" );
02636   mWrapColumnSpin->setEnabled( false ); // since !mWordWrapCheck->isChecked()
02637   connect( mWrapColumnSpin, SIGNAL( valueChanged(int) ),
02638            this, SLOT( slotEmitChanged( void ) ) );
02639 
02640   hlay->addWidget( mWrapColumnSpin );
02641   hlay->addStretch( 1 );
02642   // only enable the spinbox if the checkbox is checked:
02643   connect( mWordWrapCheck, SIGNAL(toggled(bool)),
02644            mWrapColumnSpin, SLOT(setEnabled(bool)) );
02645 
02646   hlay = new QHBoxLayout( vlay ); // inherits spacing
02647   mAutoSave = new KIntSpinBox( 0, 60, 1, 1, 10, this, "kcfg_AutosaveInterval" );
02648   label = new QLabel( mAutoSave,
02649            GlobalSettings::self()->autosaveIntervalItem()->label(), this );
02650   hlay->addWidget( label );
02651   hlay->addWidget( mAutoSave );
02652   mAutoSave->setSpecialValueText( i18n("No autosave") );
02653   mAutoSave->setSuffix( i18n(" min") );
02654   hlay->addStretch( 1 );
02655   connect( mAutoSave, SIGNAL( valueChanged(int) ),
02656            this, SLOT( slotEmitChanged( void ) ) );
02657 
02658   hlay = new QHBoxLayout( vlay ); // inherits spacing
02659   QPushButton *completionOrderBtn = new QPushButton( i18n( "Configure Completion Order" ), this );
02660   connect( completionOrderBtn, SIGNAL( clicked() ),
02661            this, SLOT( slotConfigureCompletionOrder() ) );
02662   hlay->addWidget( completionOrderBtn );
02663   hlay->addItem( new QSpacerItem(0, 0) );
02664 
02665   // recent addresses
02666   hlay = new QHBoxLayout( vlay ); // inherits spacing
02667   QPushButton *recentAddressesBtn = new QPushButton( i18n( "Edit Recent Addresses..." ), this );
02668   connect( recentAddressesBtn, SIGNAL( clicked() ),
02669            this, SLOT( slotConfigureRecentAddresses() ) );
02670   hlay->addWidget( recentAddressesBtn );
02671   hlay->addItem( new QSpacerItem(0, 0) );
02672 
02673   // The "external editor" group:
02674   group = new QVGroupBox( i18n("External Editor"), this );
02675   group->layout()->setSpacing( KDialog::spacingHint() );
02676 
02677   mExternalEditorCheck = new QCheckBox(
02678            GlobalSettings::self()->useExternalEditorItem()->label(),
02679            group, "kcfg_UseExternalEditor" );
02680   connect( mExternalEditorCheck, SIGNAL( toggled( bool ) ),
02681            this, SLOT( slotEmitChanged( void ) ) );
02682 
02683   hbox = new QHBox( group );
02684   label = new QLabel( GlobalSettings::self()->externalEditorItem()->label(),
02685                    hbox );
02686   mEditorRequester = new KURLRequester( hbox, "kcfg_ExternalEditor" );
02687   connect( mEditorRequester, SIGNAL( urlSelected(const QString&) ),
02688            this, SLOT( slotEmitChanged( void ) ) );
02689   connect( mEditorRequester, SIGNAL( textChanged(const QString&) ),
02690            this, SLOT( slotEmitChanged( void ) ) );
02691 
02692   hbox->setStretchFactor( mEditorRequester, 1 );
02693   label->setBuddy( mEditorRequester );
02694   label->setEnabled( false ); // since !mExternalEditorCheck->isChecked()
02695   // ### FIXME: allow only executables (x-bit when available..)
02696   mEditorRequester->setFilter( "application/x-executable "
02697                                "application/x-shellscript "
02698                                "application/x-desktop" );
02699   mEditorRequester->setEnabled( false ); // !mExternalEditorCheck->isChecked()
02700   connect( mExternalEditorCheck, SIGNAL(toggled(bool)),
02701            label, SLOT(setEnabled(bool)) );
02702   connect( mExternalEditorCheck, SIGNAL(toggled(bool)),
02703            mEditorRequester, SLOT(setEnabled(bool)) );
02704 
02705   label = new QLabel( i18n("<b>%f</b> will be replaced with the "
02706                            "filename to edit."), group );
02707   label->setEnabled( false ); // see above
02708   connect( mExternalEditorCheck, SIGNAL(toggled(bool)),
02709            label, SLOT(setEnabled(bool)) );
02710 
02711   vlay->addWidget( group );
02712   vlay->addStretch( 100 );
02713 }
02714 
02715 void ComposerPage::GeneralTab::doLoadFromGlobalSettings() {
02716   // various check boxes:
02717 
02718   mAutoAppSignFileCheck->setChecked(
02719            GlobalSettings::self()->autoTextSignature()=="auto" );
02720   mTopQuoteCheck->setChecked( GlobalSettings::self()->prependSignature() );
02721   mSmartQuoteCheck->setChecked( GlobalSettings::self()->smartQuote() );
02722   mAutoRequestMDNCheck->setChecked( GlobalSettings::self()->requestMDN() );
02723   mWordWrapCheck->setChecked( GlobalSettings::self()->wordWrap() );
02724 
02725   mWrapColumnSpin->setValue( GlobalSettings::self()->lineWrapWidth() );
02726   mAutoSave->setValue( GlobalSettings::self()->autosaveInterval() );
02727 
02728   // editor group:
02729   mExternalEditorCheck->setChecked( GlobalSettings::self()->useExternalEditor() );
02730   mEditorRequester->setURL( GlobalSettings::self()->externalEditor() );
02731 }
02732 
02733 void ComposerPage::GeneralTab::installProfile( KConfig * profile ) {
02734   KConfigGroup composer( profile, "Composer" );
02735   KConfigGroup general( profile, "General" );
02736 
02737   if ( composer.hasKey( "signature" ) ) {
02738     bool state = composer.readBoolEntry("signature");
02739     mAutoAppSignFileCheck->setChecked( state );
02740   }
02741   if ( composer.hasKey( "prepend-signature" ) )
02742     mTopQuoteCheck->setChecked( composer.readBoolEntry( "prepend-signature" ) );
02743   if ( composer.hasKey( "smart-quote" ) )
02744     mSmartQuoteCheck->setChecked( composer.readBoolEntry( "smart-quote" ) );
02745   if ( composer.hasKey( "request-mdn" ) )
02746     mAutoRequestMDNCheck->setChecked( composer.readBoolEntry( "request-mdn" ) );
02747   if ( composer.hasKey( "word-wrap" ) )
02748     mWordWrapCheck->setChecked( composer.readBoolEntry( "word-wrap" ) );
02749   if ( composer.hasKey( "break-at" ) )
02750     mWrapColumnSpin->setValue( composer.readNumEntry( "break-at" ) );
02751   if ( composer.hasKey( "autosave" ) )
02752     mAutoSave->setValue( composer.readNumEntry( "autosave" ) );
02753 
02754   if ( general.hasKey( "use-external-editor" )
02755        && general.hasKey( "external-editor" ) ) {
02756     mExternalEditorCheck->setChecked( general.readBoolEntry( "use-external-editor" ) );
02757     mEditorRequester->setURL( general.readPathEntry( "external-editor" ) );
02758   }
02759 }
02760 
02761 void ComposerPage::GeneralTab::save() {
02762   GlobalSettings::self()->setAutoTextSignature(
02763          mAutoAppSignFileCheck->isChecked() ? "auto" : "manual" );
02764   GlobalSettings::self()->setPrependSignature( mTopQuoteCheck->isChecked());
02765   GlobalSettings::self()->setSmartQuote( mSmartQuoteCheck->isChecked() );
02766   GlobalSettings::self()->setRequestMDN( mAutoRequestMDNCheck->isChecked() );
02767   GlobalSettings::self()->setWordWrap( mWordWrapCheck->isChecked() );
02768 
02769   GlobalSettings::self()->setLineWrapWidth( mWrapColumnSpin->value() );
02770   GlobalSettings::self()->setAutosaveInterval( mAutoSave->value() );
02771 
02772   // editor group:
02773   GlobalSettings::self()->setUseExternalEditor( mExternalEditorCheck->isChecked() );
02774   GlobalSettings::self()->setExternalEditor( mEditorRequester->url() );
02775 }
02776 
02777 void ComposerPage::GeneralTab::slotConfigureRecentAddresses( )
02778 {
02779   KRecentAddress::RecentAddressDialog dlg( this );
02780   dlg.setAddresses( RecentAddresses::self( KMKernel::config() )->addresses() );
02781   if ( dlg.exec() ) {
02782     RecentAddresses::self( KMKernel::config() )->clear();
02783     const QStringList &addrList = dlg.addresses();
02784     QStringList::ConstIterator it;
02785     for ( it = addrList.constBegin(); it != addrList.constEnd(); ++it )
02786       RecentAddresses::self( KMKernel::config() )->add( *it );
02787   }
02788 }
02789 
02790 void ComposerPage::GeneralTab::slotConfigureCompletionOrder( )
02791 {
02792   KPIM::LdapSearch search;
02793   KPIM::CompletionOrderEditor editor( &search, this );
02794   editor.exec();
02795 }
02796 
02797 QString ComposerPage::PhrasesTab::helpAnchor() const {
02798   return QString::fromLatin1("configure-composer-phrases");
02799 }
02800 
02801 ComposerPagePhrasesTab::ComposerPagePhrasesTab( QWidget * parent, const char * name )
02802   : ConfigModuleTab( parent, name )
02803 {
02804   // tmp. vars:
02805   QGridLayout *glay;
02806   QPushButton *button;
02807 
02808   glay = new QGridLayout( this, 7, 3, KDialog::spacingHint() );
02809   glay->setMargin( KDialog::marginHint() );
02810   glay->setColStretch( 1, 1 );
02811   glay->setColStretch( 2, 1 );
02812   glay->setRowStretch( 7, 1 );
02813 
02814   // row 0: help text
02815   glay->addMultiCellWidget( new QLabel( i18n("<qt>The following placeholders are "
02816                                              "supported in the reply phrases:<br>"
02817                                              "<b>%D</b>: date, <b>%S</b>: subject,<br>"
02818                                              "<b>%e</b>: sender's address, <b>%F</b>: sender's name, <b>%f</b>: sender's initials,<br>"
02819                                              "<b>%T</b>: recipient's name, <b>%t</b>: recipient's name and address,<br>"
02820                                              "<b>%C</b>: carbon copy names, <b>%c</b>: carbon copy names and addresses,<br>"
02821                                              "<b>%%</b>: percent sign, <b>%_</b>: space, "
02822                                              "<b>%L</b>: linebreak</qt>"), this ),
02823                             0, 0, 0, 2 ); // row 0; cols 0..2
02824 
02825   // row 1: label and language combo box:
02826   mPhraseLanguageCombo = new LanguageComboBox( false, this );
02827   glay->addWidget( new QLabel( mPhraseLanguageCombo,
02828                                i18n("Lang&uage:"), this ), 1, 0 );
02829   glay->addMultiCellWidget( mPhraseLanguageCombo, 1, 1, 1, 2 );
02830   connect( mPhraseLanguageCombo, SIGNAL(activated(const QString&)),
02831            this, SLOT(slotLanguageChanged(const QString&)) );
02832 
02833   // row 2: "add..." and "remove" push buttons:
02834   button = new QPushButton( i18n("A&dd..."), this );
02835   button->setAutoDefault( false );
02836   glay->addWidget( button, 2, 1 );
02837   mRemoveButton = new QPushButton( i18n("Re&move"), this );
02838   mRemoveButton->setAutoDefault( false );
02839   mRemoveButton->setEnabled( false ); // combo doesn't contain anything...
02840   glay->addWidget( mRemoveButton, 2, 2 );
02841   connect( button, SIGNAL(clicked()),
02842            this, SLOT(slotNewLanguage()) );
02843   connect( mRemoveButton, SIGNAL(clicked()),
02844            this, SLOT(slotRemoveLanguage()) );
02845 
02846   // row 3: "reply to sender" line edit and label:
02847   mPhraseReplyEdit = new KLineEdit( this );
02848   connect( mPhraseReplyEdit, SIGNAL( textChanged( const QString& ) ),
02849            this, SLOT( slotEmitChanged( void ) ) );
02850   glay->addWidget( new QLabel( mPhraseReplyEdit,
02851                                i18n("Reply to se&nder:"), this ), 3, 0 );
02852   glay->addMultiCellWidget( mPhraseReplyEdit, 3, 3, 1, 2 ); // cols 1..2
02853 
02854   // row 4: "reply to all" line edit and label:
02855   mPhraseReplyAllEdit = new KLineEdit( this );
02856   connect( mPhraseReplyAllEdit, SIGNAL( textChanged( const QString& ) ),
02857            this, SLOT( slotEmitChanged( void ) ) );
02858   glay->addWidget( new QLabel( mPhraseReplyAllEdit,
02859                                i18n("Repl&y to all:"), this ), 4, 0 );
02860   glay->addMultiCellWidget( mPhraseReplyAllEdit, 4, 4, 1, 2 ); // cols 1..2
02861 
02862   // row 5: "forward" line edit and label:
02863   mPhraseForwardEdit = new KLineEdit( this );
02864   connect( mPhraseForwardEdit, SIGNAL( textChanged( const QString& ) ),
02865            this, SLOT( slotEmitChanged( void ) ) );
02866   glay->addWidget( new QLabel( mPhraseForwardEdit,
02867                                i18n("&Forward:"), this ), 5, 0 );
02868   glay->addMultiCellWidget( mPhraseForwardEdit, 5, 5, 1, 2 ); // cols 1..2
02869 
02870   // row 6: "quote indicator" line edit and label:
02871   mPhraseIndentPrefixEdit = new KLineEdit( this );
02872   connect( mPhraseIndentPrefixEdit, SIGNAL( textChanged( const QString& ) ),
02873            this, SLOT( slotEmitChanged( void ) ) );
02874   glay->addWidget( new QLabel( mPhraseIndentPrefixEdit,
02875                                i18n("&Quote indicator:"), this ), 6, 0 );
02876   glay->addMultiCellWidget( mPhraseIndentPrefixEdit, 6, 6, 1, 2 );
02877 
02878   // row 7: spacer
02879 }
02880 
02881 
02882 void ComposerPage::PhrasesTab::setLanguageItemInformation( int index ) {
02883   assert( 0 <= index && index < (int)mLanguageList.count() );
02884 
02885   LanguageItem &l = *mLanguageList.at( index );
02886 
02887   mPhraseReplyEdit->setText( l.mReply );
02888   mPhraseReplyAllEdit->setText( l.mReplyAll );
02889   mPhraseForwardEdit->setText( l.mForward );
02890   mPhraseIndentPrefixEdit->setText( l.mIndentPrefix );
02891 }
02892 
02893 void ComposerPage::PhrasesTab::saveActiveLanguageItem() {
02894   int index = mActiveLanguageItem;
02895   if (index == -1) return;
02896   assert( 0 <= index && index < (int)mLanguageList.count() );
02897 
02898   LanguageItem &l = *mLanguageList.at( index );
02899 
02900   l.mReply = mPhraseReplyEdit->text();
02901   l.mReplyAll = mPhraseReplyAllEdit->text();
02902   l.mForward = mPhraseForwardEdit->text();
02903   l.mIndentPrefix = mPhraseIndentPrefixEdit->text();
02904 }
02905 
02906 void ComposerPage::PhrasesTab::slotNewLanguage()
02907 {
02908   NewLanguageDialog dialog( mLanguageList, parentWidget(), "New", true );
02909   if ( dialog.exec() == QDialog::Accepted ) slotAddNewLanguage( dialog.language() );
02910 }
02911 
02912 void ComposerPage::PhrasesTab::slotAddNewLanguage( const QString& lang )
02913 {
02914   mPhraseLanguageCombo->setCurrentItem(
02915     mPhraseLanguageCombo->insertLanguage( lang ) );
02916   KLocale locale("kmail");
02917   locale.setLanguage( lang );
02918   mLanguageList.append(
02919      LanguageItem( lang,
02920                    locale.translate("On %D, you wrote:"),
02921                    locale.translate("On %D, %F wrote:"),
02922                    locale.translate("Forwarded Message"),
02923                    locale.translate(">%_") ) );
02924   mRemoveButton->setEnabled( true );
02925   slotLanguageChanged( QString::null );
02926 }
02927 
02928 void ComposerPage::PhrasesTab::slotRemoveLanguage()
02929 {
02930   assert( mPhraseLanguageCombo->count() > 1 );
02931   int index = mPhraseLanguageCombo->currentItem();
02932   assert( 0 <= index && index < (int)mLanguageList.count() );
02933 
02934   // remove current item from internal list and combobox:
02935   mLanguageList.remove( mLanguageList.at( index ) );
02936   mPhraseLanguageCombo->removeItem( index );
02937 
02938   if ( index >= (int)mLanguageList.count() ) index--;
02939 
02940   mActiveLanguageItem = index;
02941   setLanguageItemInformation( index );
02942   mRemoveButton->setEnabled( mLanguageList.count() > 1 );
02943   emit changed( true );
02944 }
02945 
02946 void ComposerPage::PhrasesTab::slotLanguageChanged( const QString& )
02947 {
02948   int index = mPhraseLanguageCombo->currentItem();
02949   assert( index < (int)mLanguageList.count() );
02950   saveActiveLanguageItem();
02951   mActiveLanguageItem = index;
02952   setLanguageItemInformation( index );
02953   emit changed( true );
02954 }
02955 
02956 
02957 void ComposerPage::PhrasesTab::doLoadFromGlobalSettings() {
02958   mLanguageList.clear();
02959   mPhraseLanguageCombo->clear();
02960   mActiveLanguageItem = -1;
02961 
02962   int numLang = GlobalSettings::self()->replyLanguagesCount();
02963   int currentNr = GlobalSettings::self()->replyCurrentLanguage();
02964 
02965   // build mLanguageList and mPhraseLanguageCombo:
02966   for ( int i = 0 ; i < numLang ; i++ ) {
02967     ReplyPhrases replyPhrases( QString::number(i) );
02968     replyPhrases.readConfig();
02969     QString lang = replyPhrases.language();
02970     mLanguageList.append(
02971          LanguageItem( lang,
02972                        replyPhrases.phraseReplySender(),
02973                        replyPhrases.phraseReplyAll(),
02974                        replyPhrases.phraseForward(),
02975                        replyPhrases.indentPrefix() ) );
02976     mPhraseLanguageCombo->insertLanguage( lang );
02977   }
02978 
02979   if ( currentNr >= numLang || currentNr < 0 )
02980     currentNr = 0;
02981 
02982   if ( numLang == 0 ) {
02983     slotAddNewLanguage( KGlobal::locale()->language() );
02984   }
02985 
02986   mPhraseLanguageCombo->setCurrentItem( currentNr );
02987   mActiveLanguageItem = currentNr;
02988   setLanguageItemInformation( currentNr );
02989   mRemoveButton->setEnabled( mLanguageList.count() > 1 );
02990 }
02991 
02992 void ComposerPage::PhrasesTab::save() {
02993   GlobalSettings::self()->setReplyLanguagesCount( mLanguageList.count() );
02994   GlobalSettings::self()->setReplyCurrentLanguage( mPhraseLanguageCombo->currentItem() );
02995 
02996   saveActiveLanguageItem();
02997   LanguageItemList::Iterator it = mLanguageList.begin();
02998   for ( int i = 0 ; it != mLanguageList.end() ; ++it, ++i ) {
02999     ReplyPhrases replyPhrases( QString::number(i) );
03000     replyPhrases.setLanguage( (*it).mLanguage );
03001     replyPhrases.setPhraseReplySender( (*it).mReply );
03002     replyPhrases.setPhraseReplyAll( (*it).mReplyAll );
03003     replyPhrases.setPhraseForward( (*it).mForward );
03004     replyPhrases.setIndentPrefix( (*it).mIndentPrefix );
03005     replyPhrases.writeConfig();
03006   }
03007 }
03008 
03009 QString ComposerPage::TemplatesTab::helpAnchor() const {
03010   return QString::fromLatin1("configure-composer-templates");
03011 }
03012 
03013 ComposerPageTemplatesTab::ComposerPageTemplatesTab( QWidget * parent, const char * name )
03014   : ConfigModuleTab ( parent, name )
03015 {
03016   QVBoxLayout* vlay = new QVBoxLayout( this, 0, KDialog::spacingHint() );
03017 
03018   mWidget = new TemplatesConfiguration( this );
03019   vlay->addWidget( mWidget );
03020 
03021   connect( mWidget, SIGNAL( changed() ),
03022            this, SLOT( slotEmitChanged( void ) ) );
03023 }
03024 
03025 void ComposerPage::TemplatesTab::doLoadFromGlobalSettings() {
03026     mWidget->loadFromGlobal();
03027 }
03028 
03029 void ComposerPage::TemplatesTab::save() {
03030     mWidget->saveToGlobal();
03031 }
03032 
03033 QString ComposerPage::CustomTemplatesTab::helpAnchor() const {
03034   return QString::fromLatin1("configure-composer-custom-templates");
03035 }
03036 
03037 ComposerPageCustomTemplatesTab::ComposerPageCustomTemplatesTab( QWidget * parent, const char * name )
03038   : ConfigModuleTab ( parent, name )
03039 {
03040   QVBoxLayout* vlay = new QVBoxLayout( this, 0, KDialog::spacingHint() );
03041 
03042   mWidget = new CustomTemplates( this );
03043   vlay->addWidget( mWidget );
03044 
03045   connect( mWidget, SIGNAL( changed() ),
03046            this, SLOT( slotEmitChanged( void ) ) );
03047 }
03048 
03049 void ComposerPage::CustomTemplatesTab::doLoadFromGlobalSettings() {
03050     mWidget->load();
03051 }
03052 
03053 void ComposerPage::CustomTemplatesTab::save() {
03054     mWidget->save();
03055 }
03056 
03057 QString ComposerPage::SubjectTab::helpAnchor() const {
03058   return QString::fromLatin1("configure-composer-subject");
03059 }
03060 
03061 ComposerPageSubjectTab::ComposerPageSubjectTab( QWidget * parent, const char * name )
03062   : ConfigModuleTab( parent, name )
03063 {
03064   // tmp. vars:
03065   QVBoxLayout *vlay;
03066   QGroupBox   *group;
03067   QLabel      *label;
03068 
03069 
03070   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03071 
03072   group = new QVGroupBox( i18n("Repl&y Subject Prefixes"), this );
03073   group->layout()->setSpacing( KDialog::spacingHint() );
03074 
03075   // row 0: help text:
03076   label = new QLabel( i18n("Recognize any sequence of the following prefixes\n"
03077                            "(entries are case-insensitive regular expressions):"), group );
03078   label->setAlignment( AlignLeft|WordBreak );
03079 
03080   // row 1, string list editor:
03081   SimpleStringListEditor::ButtonCode buttonCode =
03082     static_cast<SimpleStringListEditor::ButtonCode>( SimpleStringListEditor::Add | SimpleStringListEditor::Remove | SimpleStringListEditor::Modify );
03083   mReplyListEditor =
03084     new SimpleStringListEditor( group, 0, buttonCode,
03085                                 i18n("A&dd..."), i18n("Re&move"),
03086                                 i18n("Mod&ify..."),
03087                                 i18n("Enter new reply prefix:") );
03088   connect( mReplyListEditor, SIGNAL( changed( void ) ),
03089            this, SLOT( slotEmitChanged( void ) ) );
03090 
03091   // row 2: "replace [...]" check box:
03092   mReplaceReplyPrefixCheck = new QCheckBox(
03093      GlobalSettings::self()->replaceReplyPrefixItem()->label(),
03094      group, "kcfg_ReplaceReplyPrefix" );
03095   connect( mReplaceReplyPrefixCheck, SIGNAL( stateChanged( int ) ),
03096            this, SLOT( slotEmitChanged( void ) ) );
03097 
03098   vlay->addWidget( group );
03099 
03100 
03101   group = new QVGroupBox( i18n("For&ward Subject Prefixes"), this );
03102   group->layout()->setSpacing( KDialog::marginHint() );
03103 
03104   // row 0: help text:
03105   label= new QLabel( i18n("Recognize any sequence of the following prefixes\n"
03106                           "(entries are case-insensitive regular expressions):"), group );
03107   label->setAlignment( AlignLeft|WordBreak );
03108 
03109   // row 1: string list editor
03110   mForwardListEditor =
03111     new SimpleStringListEditor( group, 0, buttonCode,
03112                                 i18n("Add..."),
03113                                 i18n("Remo&ve"),
03114                                 i18n("Modify..."),
03115                                 i18n("Enter new forward prefix:") );
03116   connect( mForwardListEditor, SIGNAL( changed( void ) ),
03117            this, SLOT( slotEmitChanged( void ) ) );
03118 
03119   // row 3: "replace [...]" check box:
03120   mReplaceForwardPrefixCheck = new QCheckBox(
03121        GlobalSettings::self()->replaceForwardPrefixItem()->label(),
03122        group, "kcfg_ReplaceForwardPrefix" );
03123   connect( mReplaceForwardPrefixCheck, SIGNAL( stateChanged( int ) ),
03124            this, SLOT( slotEmitChanged( void ) ) );
03125 
03126   vlay->addWidget( group );
03127 }
03128 
03129 void ComposerPage::SubjectTab::doLoadFromGlobalSettings() {
03130   mReplyListEditor->setStringList( GlobalSettings::self()->replyPrefixes() );
03131   mReplaceReplyPrefixCheck->setChecked( GlobalSettings::self()->replaceReplyPrefix() );
03132   mForwardListEditor->setStringList( GlobalSettings::self()->forwardPrefixes() );
03133   mReplaceForwardPrefixCheck->setChecked( GlobalSettings::self()->replaceForwardPrefix() );
03134 }
03135 
03136 void ComposerPage::SubjectTab::save() {
03137   GlobalSettings::self()->setReplyPrefixes( mReplyListEditor->stringList() );
03138   GlobalSettings::self()->setForwardPrefixes( mForwardListEditor->stringList() );
03139 }
03140 
03141 QString ComposerPage::CharsetTab::helpAnchor() const {
03142   return QString::fromLatin1("configure-composer-charset");
03143 }
03144 
03145 ComposerPageCharsetTab::ComposerPageCharsetTab( QWidget * parent, const char * name )
03146   : ConfigModuleTab( parent, name )
03147 {
03148   // tmp. vars:
03149   QVBoxLayout *vlay;
03150   QLabel      *label;
03151 
03152   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03153 
03154   label = new QLabel( i18n("This list is checked for every outgoing message "
03155                            "from the top to the bottom for a charset that "
03156                            "contains all required characters."), this );
03157   label->setAlignment( WordBreak);
03158   vlay->addWidget( label );
03159 
03160   mCharsetListEditor =
03161     new SimpleStringListEditor( this, 0, SimpleStringListEditor::All,
03162                                 i18n("A&dd..."), i18n("Remo&ve"),
03163                                 i18n("&Modify..."), i18n("Enter charset:") );
03164   connect( mCharsetListEditor, SIGNAL( changed( void ) ),
03165            this, SLOT( slotEmitChanged( void ) ) );
03166 
03167   vlay->addWidget( mCharsetListEditor, 1 );
03168 
03169   mKeepReplyCharsetCheck = new QCheckBox( i18n("&Keep original charset when "
03170                                                 "replying or forwarding (if "
03171                                                 "possible)"), this );
03172   connect( mKeepReplyCharsetCheck, SIGNAL ( stateChanged( int ) ),
03173            this, SLOT( slotEmitChanged( void ) ) );
03174   vlay->addWidget( mKeepReplyCharsetCheck );
03175 
03176   connect( mCharsetListEditor, SIGNAL(aboutToAdd(QString&)),
03177            this, SLOT(slotVerifyCharset(QString&)) );
03178 }
03179 
03180 void ComposerPage::CharsetTab::slotVerifyCharset( QString & charset ) {
03181   if ( charset.isEmpty() ) return;
03182 
03183   // KCharsets::codecForName("us-ascii") returns "iso-8859-1" (cf. Bug #49812)
03184   // therefore we have to treat this case specially
03185   if ( charset.lower() == QString::fromLatin1("us-ascii") ) {
03186     charset = QString::fromLatin1("us-ascii");
03187     return;
03188   }
03189 
03190   if ( charset.lower() == QString::fromLatin1("locale") ) {
03191     charset =  QString::fromLatin1("%1 (locale)")
03192       .arg( QCString( kmkernel->networkCodec()->mimeName() ).lower() );
03193     return;
03194   }
03195 
03196   bool ok = false;
03197   QTextCodec *codec = KGlobal::charsets()->codecForName( charset, ok );
03198   if ( ok && codec ) {
03199     charset = QString::fromLatin1( codec->mimeName() ).lower();
03200     return;
03201   }
03202 
03203   KMessageBox::sorry( this, i18n("This charset is not supported.") );
03204   charset = QString::null;
03205 }
03206 
03207 void ComposerPage::CharsetTab::doLoadOther() {
03208   KConfigGroup composer( KMKernel::config(), "Composer" );
03209 
03210   QStringList charsets = composer.readListEntry( "pref-charsets" );
03211   for ( QStringList::Iterator it = charsets.begin() ;
03212         it != charsets.end() ; ++it )
03213     if ( (*it) == QString::fromLatin1("locale") ) {
03214       QCString cset = kmkernel->networkCodec()->mimeName();
03215       KPIM::kAsciiToLower( cset.data() );
03216       (*it) = QString("%1 (locale)").arg( cset );
03217     }
03218 
03219   mCharsetListEditor->setStringList( charsets );
03220   mKeepReplyCharsetCheck->setChecked( !composer.readBoolEntry( "force-reply-charset", false ) );
03221 }
03222 
03223 void ComposerPage::CharsetTab::save() {
03224   KConfigGroup composer( KMKernel::config(), "Composer" );
03225 
03226   QStringList charsetList = mCharsetListEditor->stringList();
03227   QStringList::Iterator it = charsetList.begin();
03228   for ( ; it != charsetList.end() ; ++it )
03229     if ( (*it).endsWith("(locale)") )
03230       (*it) = "locale";
03231   composer.writeEntry( "pref-charsets", charsetList );
03232   composer.writeEntry( "force-reply-charset",
03233                        !mKeepReplyCharsetCheck->isChecked() );
03234 }
03235 
03236 QString ComposerPage::HeadersTab::helpAnchor() const {
03237   return QString::fromLatin1("configure-composer-headers");
03238 }
03239 
03240 ComposerPageHeadersTab::ComposerPageHeadersTab( QWidget * parent, const char * name )
03241   : ConfigModuleTab( parent, name )
03242 {
03243   // tmp. vars:
03244   QVBoxLayout *vlay;
03245   QHBoxLayout *hlay;
03246   QGridLayout *glay;
03247   QLabel      *label;
03248   QPushButton *button;
03249 
03250   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03251 
03252   // "Use custom Message-Id suffix" checkbox:
03253   mCreateOwnMessageIdCheck =
03254     new QCheckBox( i18n("&Use custom message-id suffix"), this );
03255   connect( mCreateOwnMessageIdCheck, SIGNAL ( stateChanged( int ) ),
03256            this, SLOT( slotEmitChanged( void ) ) );
03257   vlay->addWidget( mCreateOwnMessageIdCheck );
03258 
03259   // "Message-Id suffix" line edit and label:
03260   hlay = new QHBoxLayout( vlay ); // inherits spacing
03261   mMessageIdSuffixEdit = new KLineEdit( this );
03262   // only ASCII letters, digits, plus, minus and dots are allowed
03263   mMessageIdSuffixValidator =
03264     new QRegExpValidator( QRegExp( "[a-zA-Z0-9+-]+(?:\\.[a-zA-Z0-9+-]+)*" ), this );
03265   mMessageIdSuffixEdit->setValidator( mMessageIdSuffixValidator );
03266   label = new QLabel( mMessageIdSuffixEdit,
03267                       i18n("Custom message-&id suffix:"), this );
03268   label->setEnabled( false ); // since !mCreateOwnMessageIdCheck->isChecked()
03269   mMessageIdSuffixEdit->setEnabled( false );
03270   hlay->addWidget( label );
03271   hlay->addWidget( mMessageIdSuffixEdit, 1 );
03272   connect( mCreateOwnMessageIdCheck, SIGNAL(toggled(bool) ),
03273            label, SLOT(setEnabled(bool)) );
03274   connect( mCreateOwnMessageIdCheck, SIGNAL(toggled(bool) ),
03275            mMessageIdSuffixEdit, SLOT(setEnabled(bool)) );
03276   connect( mMessageIdSuffixEdit, SIGNAL( textChanged( const QString& ) ),
03277            this, SLOT( slotEmitChanged( void ) ) );
03278 
03279   // horizontal rule and "custom header fields" label:
03280   vlay->addWidget( new KSeparator( KSeparator::HLine, this ) );
03281   vlay->addWidget( new QLabel( i18n("Define custom mime header fields:"), this) );
03282 
03283   // "custom header fields" listbox:
03284   glay = new QGridLayout( vlay, 5, 3 ); // inherits spacing
03285   glay->setRowStretch( 2, 1 );
03286   glay->setColStretch( 1, 1 );
03287   mTagList = new ListView( this, "tagList" );
03288   mTagList->addColumn( i18n("Name") );
03289   mTagList->addColumn( i18n("Value") );
03290   mTagList->setAllColumnsShowFocus( true );
03291   mTagList->setSorting( -1 );
03292   connect( mTagList, SIGNAL(selectionChanged()),
03293            this, SLOT(slotMimeHeaderSelectionChanged()) );
03294   glay->addMultiCellWidget( mTagList, 0, 2, 0, 1 );
03295 
03296   // "new" and "remove" buttons:
03297   button = new QPushButton( i18n("Ne&w"), this );
03298   connect( button, SIGNAL(clicked()), this, SLOT(slotNewMimeHeader()) );
03299   button->setAutoDefault( false );
03300   glay->addWidget( button, 0, 2 );
03301   mRemoveHeaderButton = new QPushButton( i18n("Re&move"), this );
03302   connect( mRemoveHeaderButton, SIGNAL(clicked()),
03303            this, SLOT(slotRemoveMimeHeader()) );
03304   button->setAutoDefault( false );
03305   glay->addWidget( mRemoveHeaderButton, 1, 2 );
03306 
03307   // "name" and "value" line edits and labels:
03308   mTagNameEdit = new KLineEdit( this );
03309   mTagNameEdit->setEnabled( false );
03310   mTagNameLabel = new QLabel( mTagNameEdit, i18n("&Name:"), this );
03311   mTagNameLabel->setEnabled( false );
03312   glay->addWidget( mTagNameLabel, 3, 0 );
03313   glay->addWidget( mTagNameEdit, 3, 1 );
03314   connect( mTagNameEdit, SIGNAL(textChanged(const QString&)),
03315            this, SLOT(slotMimeHeaderNameChanged(const QString&)) );
03316 
03317   mTagValueEdit = new KLineEdit( this );
03318   mTagValueEdit->setEnabled( false );
03319   mTagValueLabel = new QLabel( mTagValueEdit, i18n("&Value:"), this );
03320   mTagValueLabel->setEnabled( false );
03321   glay->addWidget( mTagValueLabel, 4, 0 );
03322   glay->addWidget( mTagValueEdit, 4, 1 );
03323   connect( mTagValueEdit, SIGNAL(textChanged(const QString&)),
03324            this, SLOT(slotMimeHeaderValueChanged(const QString&)) );
03325 }
03326 
03327 void ComposerPage::HeadersTab::slotMimeHeaderSelectionChanged()
03328 {
03329   QListViewItem * item = mTagList->selectedItem();
03330 
03331   if ( item ) {
03332     mTagNameEdit->setText( item->text( 0 ) );
03333     mTagValueEdit->setText( item->text( 1 ) );
03334   } else {
03335     mTagNameEdit->clear();
03336     mTagValueEdit->clear();
03337   }
03338   mRemoveHeaderButton->setEnabled( item );
03339   mTagNameEdit->setEnabled( item );
03340   mTagValueEdit->setEnabled( item );
03341   mTagNameLabel->setEnabled( item );
03342   mTagValueLabel->setEnabled( item );
03343 }
03344 
03345 
03346 void ComposerPage::HeadersTab::slotMimeHeaderNameChanged( const QString & text ) {
03347   // is called on ::setup(), when clearing the line edits. So be
03348   // prepared to not find a selection:
03349   QListViewItem * item = mTagList->selectedItem();
03350   if ( item )
03351     item->setText( 0, text );
03352   emit changed( true );
03353 }
03354 
03355 
03356 void ComposerPage::HeadersTab::slotMimeHeaderValueChanged( const QString & text ) {
03357   // is called on ::setup(), when clearing the line edits. So be
03358   // prepared to not find a selection:
03359   QListViewItem * item = mTagList->selectedItem();
03360   if ( item )
03361     item->setText( 1, text );
03362   emit changed( true );
03363 }
03364 
03365 
03366 void ComposerPage::HeadersTab::slotNewMimeHeader()
03367 {
03368   QListViewItem *listItem = new QListViewItem( mTagList );
03369   mTagList->setCurrentItem( listItem );
03370   mTagList->setSelected( listItem, true );
03371   emit changed( true );
03372 }
03373 
03374 
03375 void ComposerPage::HeadersTab::slotRemoveMimeHeader()
03376 {
03377   // calling this w/o selection is a programming error:
03378   QListViewItem * item = mTagList->selectedItem();
03379   if ( !item ) {
03380     kdDebug(5006) << "==================================================\n"
03381                   << "Error: Remove button was pressed although no custom header was selected\n"
03382                   << "==================================================\n";
03383     return;
03384   }
03385 
03386   QListViewItem * below = item->nextSibling();
03387   delete item;
03388 
03389   if ( below )
03390     mTagList->setSelected( below, true );
03391   else if ( mTagList->lastItem() )
03392     mTagList->setSelected( mTagList->lastItem(), true );
03393   emit changed( true );
03394 }
03395 
03396 void ComposerPage::HeadersTab::doLoadOther() {
03397   KConfigGroup general( KMKernel::config(), "General" );
03398 
03399   QString suffix = general.readEntry( "myMessageIdSuffix" );
03400   mMessageIdSuffixEdit->setText( suffix );
03401   bool state = ( !suffix.isEmpty() &&
03402             general.readBoolEntry( "useCustomMessageIdSuffix", false ) );
03403   mCreateOwnMessageIdCheck->setChecked( state );
03404 
03405   mTagList->clear();
03406   mTagNameEdit->clear();
03407   mTagValueEdit->clear();
03408 
03409   QListViewItem * item = 0;
03410 
03411   int count = general.readNumEntry( "mime-header-count", 0 );
03412   for( int i = 0 ; i < count ; i++ ) {
03413     KConfigGroup config( KMKernel::config(),
03414                          QCString("Mime #") + QCString().setNum(i) );
03415     QString name  = config.readEntry( "name" );
03416     QString value = config.readEntry( "value" );
03417     if( !name.isEmpty() )
03418       item = new QListViewItem( mTagList, item, name, value );
03419   }
03420   if ( mTagList->childCount() ) {
03421     mTagList->setCurrentItem( mTagList->firstChild() );
03422     mTagList->setSelected( mTagList->firstChild(), true );
03423   }
03424   else {
03425     // disable the "Remove" button
03426     mRemoveHeaderButton->setEnabled( false );
03427   }
03428 }
03429 
03430 void ComposerPage::HeadersTab::save() {
03431   KConfigGroup general( KMKernel::config(), "General" );
03432 
03433   general.writeEntry( "useCustomMessageIdSuffix",
03434                       mCreateOwnMessageIdCheck->isChecked() );
03435   general.writeEntry( "myMessageIdSuffix",
03436                       mMessageIdSuffixEdit->text() );
03437 
03438   int numValidEntries = 0;
03439   QListViewItem * item = mTagList->firstChild();
03440   for ( ; item ; item = item->itemBelow() )
03441     if( !item->text(0).isEmpty() ) {
03442       KConfigGroup config( KMKernel::config(), QCString("Mime #")
03443                              + QCString().setNum( numValidEntries ) );
03444       config.writeEntry( "name",  item->text( 0 ) );
03445       config.writeEntry( "value", item->text( 1 ) );
03446       numValidEntries++;
03447     }
03448   general.writeEntry( "mime-header-count", numValidEntries );
03449 }
03450 
03451 QString ComposerPage::AttachmentsTab::helpAnchor() const {
03452   return QString::fromLatin1("configure-composer-attachments");
03453 }
03454 
03455 ComposerPageAttachmentsTab::ComposerPageAttachmentsTab( QWidget * parent,
03456                                                         const char * name )
03457   : ConfigModuleTab( parent, name ) {
03458   // tmp. vars:
03459   QVBoxLayout *vlay;
03460   QLabel      *label;
03461 
03462   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03463 
03464   // "Outlook compatible attachment naming" check box
03465   mOutlookCompatibleCheck =
03466     new QCheckBox( i18n( "Outlook-compatible attachment naming" ), this );
03467   mOutlookCompatibleCheck->setChecked( false );
03468   QToolTip::add( mOutlookCompatibleCheck, i18n(
03469     "Turn this option on to make Outlook(tm) understand attachment names "
03470     "containing non-English characters" ) );
03471   connect( mOutlookCompatibleCheck, SIGNAL( stateChanged( int ) ),
03472            this, SLOT( slotEmitChanged( void ) ) );
03473   connect( mOutlookCompatibleCheck, SIGNAL( clicked() ),
03474            this, SLOT( slotOutlookCompatibleClicked() ) );
03475   vlay->addWidget( mOutlookCompatibleCheck );
03476   vlay->addSpacing( 5 );
03477 
03478   // "Enable detection of missing attachments" check box
03479   mMissingAttachmentDetectionCheck =
03480     new QCheckBox( i18n("E&nable detection of missing attachments"), this );
03481   mMissingAttachmentDetectionCheck->setChecked( true );
03482   connect( mMissingAttachmentDetectionCheck, SIGNAL( stateChanged( int ) ),
03483            this, SLOT( slotEmitChanged( void ) ) );
03484   vlay->addWidget( mMissingAttachmentDetectionCheck );
03485 
03486   // "Attachment key words" label and string list editor
03487   label = new QLabel( i18n("Recognize any of the following key words as "
03488                            "intention to attach a file:"), this );
03489   label->setAlignment( AlignLeft|WordBreak );
03490   vlay->addWidget( label );
03491 
03492   SimpleStringListEditor::ButtonCode buttonCode =
03493     static_cast<SimpleStringListEditor::ButtonCode>( SimpleStringListEditor::Add | SimpleStringListEditor::Remove | SimpleStringListEditor::Modify );
03494   mAttachWordsListEditor =
03495     new SimpleStringListEditor( this, 0, buttonCode,
03496                                 i18n("A&dd..."), i18n("Re&move"),
03497                                 i18n("Mod&ify..."),
03498                                 i18n("Enter new key word:") );
03499   connect( mAttachWordsListEditor, SIGNAL( changed( void ) ),
03500            this, SLOT( slotEmitChanged( void ) ) );
03501   vlay->addWidget( mAttachWordsListEditor );
03502 
03503   connect( mMissingAttachmentDetectionCheck, SIGNAL(toggled(bool) ),
03504            label, SLOT(setEnabled(bool)) );
03505   connect( mMissingAttachmentDetectionCheck, SIGNAL(toggled(bool) ),
03506            mAttachWordsListEditor, SLOT(setEnabled(bool)) );
03507 }
03508 
03509 void ComposerPage::AttachmentsTab::doLoadFromGlobalSettings() {
03510   mOutlookCompatibleCheck->setChecked(
03511     GlobalSettings::self()->outlookCompatibleAttachments() );
03512   mMissingAttachmentDetectionCheck->setChecked(
03513     GlobalSettings::self()->showForgottenAttachmentWarning() );
03514   QStringList attachWordsList = GlobalSettings::self()->attachmentKeywords();
03515   if ( attachWordsList.isEmpty() ) {
03516     // default value
03517     attachWordsList << QString::fromLatin1("attachment")
03518                     << QString::fromLatin1("attached");
03519     if ( QString::fromLatin1("attachment") != i18n("attachment") )
03520       attachWordsList << i18n("attachment");
03521     if ( QString::fromLatin1("attached") != i18n("attached") )
03522       attachWordsList << i18n("attached");
03523   }
03524 
03525   mAttachWordsListEditor->setStringList( attachWordsList );
03526 }
03527 
03528 void ComposerPage::AttachmentsTab::save() {
03529   GlobalSettings::self()->setOutlookCompatibleAttachments(
03530     mOutlookCompatibleCheck->isChecked() );
03531   GlobalSettings::self()->setShowForgottenAttachmentWarning(
03532     mMissingAttachmentDetectionCheck->isChecked() );
03533   GlobalSettings::self()->setAttachmentKeywords(
03534     mAttachWordsListEditor->stringList() );
03535 }
03536 
03537 void ComposerPageAttachmentsTab::slotOutlookCompatibleClicked()
03538 {
03539   if (mOutlookCompatibleCheck->isChecked()) {
03540     KMessageBox::information(0,i18n("You have chosen to "
03541     "encode attachment names containing non-English characters in a way that "
03542     "is understood by Outlook(tm) and other mail clients that do not "
03543     "support standard-compliant encoded attachment names.\n"
03544     "Note that KMail may create non-standard compliant messages, "
03545     "and consequently it is possible that your messages will not be "
03546     "understood by standard-compliant mail clients; so, unless you have no "
03547     "other choice, you should not enable this option." ) );
03548   }
03549 }
03550 
03551 // *************************************************************
03552 // *                                                           *
03553 // *                      SecurityPage                         *
03554 // *                                                           *
03555 // *************************************************************
03556 QString SecurityPage::helpAnchor() const {
03557   return QString::fromLatin1("configure-security");
03558 }
03559 
03560 SecurityPage::SecurityPage( QWidget * parent, const char * name )
03561   : ConfigModuleWithTabs( parent, name )
03562 {
03563   //
03564   // "Reading" tab:
03565   //
03566   mGeneralTab = new GeneralTab(); //  @TODO: rename
03567   addTab( mGeneralTab, i18n("&Reading") );
03568 
03569   //
03570   // "Composing" tab:
03571   //
03572   mComposerCryptoTab = new ComposerCryptoTab();
03573   addTab( mComposerCryptoTab, i18n("Composing") );
03574 
03575   //
03576   // "Warnings" tab:
03577   //
03578   mWarningTab = new WarningTab();
03579   addTab( mWarningTab, i18n("Warnings") );
03580 
03581   //
03582   // "S/MIME Validation" tab:
03583   //
03584   mSMimeTab = new SMimeTab();
03585   addTab( mSMimeTab, i18n("S/MIME &Validation") );
03586 
03587   //
03588   // "Crypto Backends" tab:
03589   //
03590   mCryptPlugTab = new CryptPlugTab();
03591   addTab( mCryptPlugTab, i18n("Crypto Backe&nds") );
03592   load();
03593 }
03594 
03595 
03596 void SecurityPage::installProfile( KConfig * profile ) {
03597   mGeneralTab->installProfile( profile );
03598   mComposerCryptoTab->installProfile( profile );
03599   mWarningTab->installProfile( profile );
03600   mSMimeTab->installProfile( profile );
03601 }
03602 
03603 QString SecurityPage::GeneralTab::helpAnchor() const {
03604   return QString::fromLatin1("configure-security-reading");
03605 }
03606 
03607 SecurityPageGeneralTab::SecurityPageGeneralTab( QWidget * parent, const char * name )
03608   : ConfigModuleTab ( parent, name )
03609 {
03610   // tmp. vars:
03611   QVBoxLayout  *vlay;
03612   QHBox        *hbox;
03613   QGroupBox    *group;
03614   QRadioButton *radio;
03615   KActiveLabel *label;
03616   QWidget      *w;
03617   QString       msg;
03618 
03619   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
03620 
03621   // QWhat'sThis texts
03622   QString htmlWhatsThis = i18n( "<qt><p>Messages sometimes come in both formats. "
03623               "This option controls whether you want the HTML part or the plain "
03624               "text part to be displayed.</p>"
03625               "<p>Displaying the HTML part makes the message look better, "
03626               "but at the same time increases the risk of security holes "
03627               "being exploited.</p>"
03628               "<p>Displaying the plain text part loses much of the message's "
03629               "formatting, but makes it almost <em>impossible</em> "
03630               "to exploit security holes in the HTML renderer (Konqueror).</p>"
03631               "<p>The option below guards against one common misuse of HTML "
03632               "messages, but it cannot guard against security issues that were "
03633               "not known at the time this version of KMail was written.</p>"
03634               "<p>It is therefore advisable to <em>not</em> prefer HTML to "
03635               "plain text.</p>"
03636               "<p><b>Note:</b> You can set this option on a per-folder basis "
03637               "from the <i>Folder</i> menu of KMail's main window.</p></qt>" );
03638 
03639   QString externalWhatsThis = i18n( "<qt><p>Some mail advertisements are in HTML "
03640               "and contain references to, for example, images that the advertisers"
03641               " employ to find out that you have read their message "
03642               "(&quot;web bugs&quot;).</p>"
03643               "<p>There is no valid reason to load images off the Internet like "
03644               "this, since the sender can always attach the required images "
03645               "directly to the message.</p>"
03646               "<p>To guard from such a misuse of the HTML displaying feature "
03647               "of KMail, this option is <em>disabled</em> by default.</p>"
03648               "<p>However, if you wish to, for example, view images in HTML "
03649               "messages that were not attached to it, you can enable this "
03650               "option, but you should be aware of the possible problem.</p></qt>" );
03651 
03652   QString receiptWhatsThis = i18n( "<qt><h3>Message Disposition "
03653               "Notification Policy</h3>"
03654               "<p>MDNs are a generalization of what is commonly called <b>read "
03655               "receipt</b>. The message author requests a disposition "
03656               "notification to be sent and the receiver's mail program "
03657               "generates a reply from which the author can learn what "
03658               "happened to his message. Common disposition types include "
03659               "<b>displayed</b> (i.e. read), <b>deleted</b> and <b>dispatched</b> "
03660               "(e.g. forwarded).</p>"
03661               "<p>The following options are available to control KMail's "
03662               "sending of MDNs:</p>"
03663               "<ul>"
03664               "<li><em>Ignore</em>: Ignores any request for disposition "
03665               "notifications. No MDN will ever be sent automatically "
03666               "(recommended).</li>"
03667               "<li><em>Ask</em>: Answers requests only after asking the user "
03668               "for permission. This way, you can send MDNs for selected "
03669               "messages while denying or ignoring them for others.</li>"
03670               "<li><em>Deny</em>: Always sends a <b>denied</b> notification. This "
03671               "is only <em>slightly</em> better than always sending MDNs. "
03672               "The author will still know that the messages has been acted "
03673               "upon, he just cannot tell whether it was deleted or read etc.</li>"
03674               "<li><em>Always send</em>: Always sends the requested "
03675               "disposition notification. That means that the author of the "
03676               "message gets to know when the message was acted upon and, "
03677               "in addition, what happened to it (displayed, deleted, "
03678               "etc.). This option is strongly discouraged, but since it "
03679               "makes much sense e.g. for customer relationship management, "
03680               "it has been made available.</li>"
03681               "</ul></qt>" );
03682 
03683 
03684   // "HTML Messages" group box:
03685   group = new QVGroupBox( i18n( "HTML Messages" ), this );
03686   group->layout()->setSpacing( KDialog::spacingHint() );
03687 
03688   mHtmlMailCheck = new QCheckBox( i18n("Prefer H&TML to plain text"), group );
03689   QWhatsThis::add( mHtmlMailCheck, htmlWhatsThis );
03690   connect( mHtmlMailCheck, SIGNAL( stateChanged( int ) ),
03691            this, SLOT( slotEmitChanged( void ) ) );
03692   mExternalReferences = new QCheckBox( i18n("Allow messages to load e&xternal "
03693                                             "references from the Internet" ), group );
03694   QWhatsThis::add( mExternalReferences, externalWhatsThis );
03695   connect( mExternalReferences, SIGNAL( stateChanged( int ) ),
03696            this, SLOT( slotEmitChanged( void ) ) );
03697   label = new KActiveLabel( i18n("<b>WARNING:</b> Allowing HTML in email may "
03698                            "increase the risk that your system will be "
03699                            "compromised by present and anticipated security "
03700                            "exploits. <a href=\"whatsthis:%1\">More about "
03701                            "HTML mails...</a> <a href=\"whatsthis:%2\">More "
03702                            "about external references...</a>")
03703                            .arg(htmlWhatsThis).arg(externalWhatsThis),
03704                            group );
03705 
03706   vlay->addWidget( group );
03707 
03708   // encrypted messages group
03709   group = new QVGroupBox( i18n("Encrypted Messages"), this );
03710   group->layout()->setSpacing( KDialog::spacingHint() );
03711   mAlwaysDecrypt = new QCheckBox( i18n( "Attempt decryption of encrypted messages when viewing" ), group );
03712   connect( mAlwaysDecrypt, SIGNAL(stateChanged(int)), this, SLOT(slotEmitChanged()) );
03713   vlay->addWidget( group );
03714 
03715   // "Message Disposition Notification" groupbox:
03716   group = new QVGroupBox( i18n("Message Disposition Notifications"), this );
03717   group->layout()->setSpacing( KDialog::spacingHint() );
03718 
03719 
03720   // "ignore", "ask", "deny", "always send" radiobutton line:
03721   mMDNGroup = new QButtonGroup( group );
03722   mMDNGroup->hide();
03723   connect( mMDNGroup, SIGNAL( clicked( int ) ),
03724            this, SLOT( slotEmitChanged( void ) ) );
03725   hbox = new QHBox( group );
03726   hbox->setSpacing( KDialog::spacingHint() );
03727 
03728   (void)new QLabel( i18n("Send policy:"), hbox );
03729 
03730   radio = new QRadioButton( i18n("&Ignore"), hbox );
03731   mMDNGroup->insert( radio );
03732 
03733   radio = new QRadioButton( i18n("As&k"), hbox );
03734   mMDNGroup->insert( radio );
03735 
03736   radio = new QRadioButton( i18n("&Deny"), hbox );
03737   mMDNGroup->insert( radio );
03738 
03739   radio = new QRadioButton( i18n("Al&ways send"), hbox );
03740   mMDNGroup->insert( radio );
03741 
03742   for ( int i = 0 ; i < mMDNGroup->count() ; ++i )
03743       QWhatsThis::add( mMDNGroup->find( i ), receiptWhatsThis );
03744 
03745   w = new QWidget( hbox ); // spacer
03746   hbox->setStretchFactor( w, 1 );
03747 
03748   // "Original Message quote" radiobutton line:
03749   mOrigQuoteGroup = new QButtonGroup( group );
03750   mOrigQuoteGroup->hide();
03751   connect( mOrigQuoteGroup, SIGNAL( clicked( int ) ),
03752            this, SLOT( slotEmitChanged( void ) ) );
03753 
03754   hbox = new QHBox( group );
03755   hbox->setSpacing( KDialog::spacingHint() );
03756 
03757   (void)new QLabel( i18n("Quote original message:"), hbox );
03758 
03759   radio = new QRadioButton( i18n("Nothin&g"), hbox );
03760   mOrigQuoteGroup->insert( radio );
03761 
03762   radio = new QRadioButton( i18n("&Full message"), hbox );
03763   mOrigQuoteGroup->insert( radio );
03764 
03765   radio = new QRadioButton( i18n("Onl&y headers"), hbox );
03766   mOrigQuoteGroup->insert( radio );
03767 
03768   w = new QWidget( hbox );
03769   hbox->setStretchFactor( w, 1 );
03770 
03771   mNoMDNsWhenEncryptedCheck = new QCheckBox( i18n("Do not send MDNs in response to encrypted messages"), group );
03772   connect( mNoMDNsWhenEncryptedCheck, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
03773 
03774   // Warning label:
03775   label = new KActiveLabel( i18n("<b>WARNING:</b> Unconditionally returning "
03776                            "confirmations undermines your privacy. "
03777                            "<a href=\"whatsthis:%1\">More...</a>")
03778                              .arg(receiptWhatsThis),
03779                            group );
03780 
03781   vlay->addWidget( group );
03782 
03783   // "Attached keys" group box:
03784   group = new QVGroupBox( i18n( "Certificate && Key Bundle Attachments" ), this );
03785   group->layout()->setSpacing( KDialog::spacingHint() );
03786 
03787   mAutomaticallyImportAttachedKeysCheck = new QCheckBox( i18n("Automatically import keys and certificates"), group );
03788   connect( mAutomaticallyImportAttachedKeysCheck, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
03789 
03790   vlay->addWidget( group );
03791 
03792 
03793 
03794   vlay->addStretch( 10 ); // spacer
03795 }
03796 
03797 void SecurityPage::GeneralTab::doLoadOther() {
03798   const KConfigGroup reader( KMKernel::config(), "Reader" );
03799 
03800   mHtmlMailCheck->setChecked( reader.readBoolEntry( "htmlMail", false ) );
03801   mExternalReferences->setChecked( reader.readBoolEntry( "htmlLoadExternal", false ) );
03802   mAutomaticallyImportAttachedKeysCheck->setChecked( reader.readBoolEntry( "AutoImportKeys", false ) );
03803 
03804   mAlwaysDecrypt->setChecked( GlobalSettings::self()->alwaysDecrypt() );
03805 
03806   const KConfigGroup mdn( KMKernel::config(), "MDN" );
03807 
03808   int num = mdn.readNumEntry( "default-policy", 0 );
03809   if ( num < 0 || num >= mMDNGroup->count() ) num = 0;
03810   mMDNGroup->setButton( num );
03811   num = mdn.readNumEntry( "quote-message", 0 );
03812   if ( num < 0 || num >= mOrigQuoteGroup->count() ) num = 0;
03813   mOrigQuoteGroup->setButton( num );
03814   mNoMDNsWhenEncryptedCheck->setChecked(mdn.readBoolEntry( "not-send-when-encrypted", true ));
03815 }
03816 
03817 void SecurityPage::GeneralTab::installProfile( KConfig * profile ) {
03818   const KConfigGroup reader( profile, "Reader" );
03819   const KConfigGroup mdn( profile, "MDN" );
03820 
03821   if ( reader.hasKey( "htmlMail" ) )
03822     mHtmlMailCheck->setChecked( reader.readBoolEntry( "htmlMail" ) );
03823   if ( reader.hasKey( "htmlLoadExternal" ) )
03824     mExternalReferences->setChecked( reader.readBoolEntry( "htmlLoadExternal" ) );
03825   if ( reader.hasKey( "AutoImportKeys" ) )
03826     mAutomaticallyImportAttachedKeysCheck->setChecked( reader.readBoolEntry( "AutoImportKeys" ) );
03827 
03828   if ( mdn.hasKey( "default-policy" ) ) {
03829       int num = mdn.readNumEntry( "default-policy" );
03830       if ( num < 0 || num >= mMDNGroup->count() ) num = 0;
03831       mMDNGroup->setButton( num );
03832   }
03833   if ( mdn.hasKey( "quote-message" ) ) {
03834       int num = mdn.readNumEntry( "quote-message" );
03835       if ( num < 0 || num >= mOrigQuoteGroup->count() ) num = 0;
03836       mOrigQuoteGroup->setButton( num );
03837   }
03838   if ( mdn.hasKey( "not-send-when-encrypted" ) )
03839       mNoMDNsWhenEncryptedCheck->setChecked(mdn.readBoolEntry( "not-send-when-encrypted" ));
03840 }
03841 
03842 void SecurityPage::GeneralTab::save() {
03843   KConfigGroup reader( KMKernel::config(), "Reader" );
03844   KConfigGroup mdn( KMKernel::config(), "MDN" );
03845 
03846   if (reader.readBoolEntry( "htmlMail", false ) != mHtmlMailCheck->isChecked())
03847   {
03848     if (KMessageBox::warningContinueCancel(this, i18n("Changing the global "
03849       "HTML setting will override all folder specific values."), QString::null,
03850       KStdGuiItem::cont(), "htmlMailOverride") == KMessageBox::Continue)
03851     {
03852       reader.writeEntry( "htmlMail", mHtmlMailCheck->isChecked() );
03853       QStringList names;
03854       QValueList<QGuardedPtr<KMFolder> > folders;
03855       kmkernel->folderMgr()->createFolderList(&names, &folders);
03856       kmkernel->imapFolderMgr()->createFolderList(&names, &folders);
03857       kmkernel->dimapFolderMgr()->createFolderList(&names, &folders);
03858       kmkernel->searchFolderMgr()->createFolderList(&names, &folders);
03859       for (QValueList<QGuardedPtr<KMFolder> >::iterator it = folders.begin();
03860         it != folders.end(); ++it)
03861       {
03862         if (*it)
03863         {
03864           KConfigGroupSaver saver(KMKernel::config(),
03865             "Folder-" + (*it)->idString());
03866           KMKernel::config()->writeEntry("htmlMailOverride", false);
03867         }
03868       }
03869     }
03870   }
03871   reader.writeEntry( "htmlLoadExternal", mExternalReferences->isChecked() );
03872   reader.writeEntry( "AutoImportKeys", mAutomaticallyImportAttachedKeysCheck->isChecked() );
03873   mdn.writeEntry( "default-policy", mMDNGroup->id( mMDNGroup->selected() ) );
03874   mdn.writeEntry( "quote-message", mOrigQuoteGroup->id( mOrigQuoteGroup->selected() ) );
03875   mdn.writeEntry( "not-send-when-encrypted", mNoMDNsWhenEncryptedCheck->isChecked() );
03876   GlobalSettings::self()->setAlwaysDecrypt( mAlwaysDecrypt->isChecked() );
03877 }
03878 
03879 
03880 QString SecurityPage::ComposerCryptoTab::helpAnchor() const {
03881   return QString::fromLatin1("configure-security-composing");
03882 }
03883 
03884 SecurityPageComposerCryptoTab::SecurityPageComposerCryptoTab( QWidget * parent, const char * name )
03885   : ConfigModuleTab ( parent, name )
03886 {
03887   // the margins are inside mWidget itself
03888   QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 );
03889 
03890   mWidget = new ComposerCryptoConfiguration( this );
03891   connect( mWidget->mAutoSignature, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03892   connect( mWidget->mEncToSelf, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03893   connect( mWidget->mShowEncryptionResult, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03894   connect( mWidget->mShowKeyApprovalDlg, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03895   connect( mWidget->mAutoEncrypt, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03896   connect( mWidget->mNeverEncryptWhenSavingInDrafts, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03897   connect( mWidget->mStoreEncrypted, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) );
03898   vlay->addWidget( mWidget );
03899 }
03900 
03901 void SecurityPage::ComposerCryptoTab::doLoadOther() {
03902   const KConfigGroup composer( KMKernel::config(), "Composer" );
03903 
03904   // If you change default values, sync messagecomposer.cpp too
03905 
03906   mWidget->mAutoSignature->setChecked( composer.readBoolEntry( "pgp-auto-sign", false ) );
03907 
03908   mWidget->mEncToSelf->setChecked( composer.readBoolEntry( "crypto-encrypt-to-self", true ) );
03909   mWidget->mShowEncryptionResult->setChecked( false ); //composer.readBoolEntry( "crypto-show-encryption-result", true ) );
03910   mWidget->mShowEncryptionResult->hide();
03911   mWidget->mShowKeyApprovalDlg->setChecked( composer.readBoolEntry( "crypto-show-keys-for-approval", true ) );
03912 
03913   mWidget->mAutoEncrypt->setChecked( composer.readBoolEntry( "pgp-auto-encrypt", false ) );
03914   mWidget->mNeverEncryptWhenSavingInDrafts->setChecked( composer.readBoolEntry( "never-encrypt-drafts", true ) );
03915 
03916   mWidget->mStoreEncrypted->setChecked( composer.readBoolEntry( "crypto-store-encrypted", true ) );
03917 }
03918 
03919 void SecurityPage::ComposerCryptoTab::installProfile( KConfig * profile ) {
03920   const KConfigGroup composer( profile, "Composer" );
03921 
03922   if ( composer.hasKey( "pgp-auto-sign" ) )
03923     mWidget->mAutoSignature->setChecked( composer.readBoolEntry( "pgp-auto-sign" ) );
03924 
03925   if ( composer.hasKey( "crypto-encrypt-to-self" ) )
03926     mWidget->mEncToSelf->setChecked( composer.readBoolEntry( "crypto-encrypt-to-self" ) );
03927   if ( composer.hasKey( "crypto-show-encryption-result" ) )
03928     mWidget->mShowEncryptionResult->setChecked( composer.readBoolEntry( "crypto-show-encryption-result" ) );
03929   if ( composer.hasKey( "crypto-show-keys-for-approval" ) )
03930     mWidget->mShowKeyApprovalDlg->setChecked( composer.readBoolEntry( "crypto-show-keys-for-approval" ) );
03931   if ( composer.hasKey( "pgp-auto-encrypt" ) )
03932     mWidget->mAutoEncrypt->setChecked( composer.readBoolEntry( "pgp-auto-encrypt" ) );
03933   if ( composer.hasKey( "never-encrypt-drafts" ) )
03934     mWidget->mNeverEncryptWhenSavingInDrafts->setChecked( composer.readBoolEntry( "never-encrypt-drafts" ) );
03935 
03936   if ( composer.hasKey( "crypto-store-encrypted" ) )
03937     mWidget->mStoreEncrypted->setChecked( composer.readBoolEntry( "crypto-store-encrypted" ) );
03938 }
03939 
03940 void SecurityPage::ComposerCryptoTab::save() {
03941   KConfigGroup composer( KMKernel::config(), "Composer" );
03942 
03943   composer.writeEntry( "pgp-auto-sign", mWidget->mAutoSignature->isChecked() );
03944 
03945   composer.writeEntry( "crypto-encrypt-to-self", mWidget->mEncToSelf->isChecked() );
03946   composer.writeEntry( "crypto-show-encryption-result", mWidget->mShowEncryptionResult->isChecked() );
03947   composer.writeEntry( "crypto-show-keys-for-approval", mWidget->mShowKeyApprovalDlg->isChecked() );
03948 
03949   composer.writeEntry( "pgp-auto-encrypt", mWidget->mAutoEncrypt->isChecked() );
03950   composer.writeEntry( "never-encrypt-drafts", mWidget->mNeverEncryptWhenSavingInDrafts->isChecked() );
03951 
03952   composer.writeEntry( "crypto-store-encrypted", mWidget->mStoreEncrypted->isChecked() );
03953 }
03954 
03955 QString SecurityPage::WarningTab::helpAnchor() const {
03956   return QString::fromLatin1("configure-security-warnings");
03957 }
03958 
03959 SecurityPageWarningTab::SecurityPageWarningTab( QWidget * parent, const char * name )
03960   : ConfigModuleTab( parent, name )
03961 {
03962   // the margins are inside mWidget itself
03963   QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 );
03964 
03965   mWidget = new WarningConfiguration( this );
03966   vlay->addWidget( mWidget );
03967 
03968   connect( mWidget->warnGroupBox, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
03969   connect( mWidget->mWarnUnsigned, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
03970   connect( mWidget->warnUnencryptedCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
03971   connect( mWidget->warnReceiverNotInCertificateCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
03972   connect( mWidget->mWarnSignKeyExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
03973   connect( mWidget->mWarnSignChainCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
03974   connect( mWidget->mWarnSignRootCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
03975 
03976   connect( mWidget->mWarnEncrKeyExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
03977   connect( mWidget->mWarnEncrChainCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
03978   connect( mWidget->mWarnEncrRootCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) );
03979 
03980   connect( mWidget->enableAllWarningsPB, SIGNAL(clicked()),
03981            SLOT(slotReenableAllWarningsClicked()) );
03982 }
03983 
03984 void SecurityPage::WarningTab::doLoadOther() {
03985   const KConfigGroup composer( KMKernel::config(), "Composer" );
03986 
03987   mWidget->warnUnencryptedCB->setChecked( composer.readBoolEntry( "crypto-warning-unencrypted", false ) );
03988   mWidget->mWarnUnsigned->setChecked( composer.readBoolEntry( "crypto-warning-unsigned", false ) );
03989   mWidget->warnReceiverNotInCertificateCB->setChecked( composer.readBoolEntry( "crypto-warn-recv-not-in-cert", true ) );
03990 
03991   // The "-int" part of the key name is because there used to be a separate boolean
03992   // config entry for enabling/disabling. This is done with the single bool value now.
03993   mWidget->warnGroupBox->setChecked( composer.readBoolEntry( "crypto-warn-when-near-expire", true ) );
03994 
03995   mWidget->mWarnSignKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-key-near-expire-int", 14 ) );
03996   mWidget->mWarnSignChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int", 14 ) );
03997   mWidget->mWarnSignRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-root-near-expire-int", 14 ) );
03998 
03999   mWidget->mWarnEncrKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-key-near-expire-int", 14 ) );
04000   mWidget->mWarnEncrChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int", 14 ) );
04001   mWidget->mWarnEncrRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-root-near-expire-int", 14 ) );
04002 
04003   mWidget->enableAllWarningsPB->setEnabled( true );
04004 }
04005 
04006 void SecurityPage::WarningTab::installProfile( KConfig * profile ) {
04007   const KConfigGroup composer( profile, "Composer" );
04008 
04009   if ( composer.hasKey( "crypto-warning-unencrypted" ) )
04010     mWidget->warnUnencryptedCB->setChecked( composer.readBoolEntry( "crypto-warning-unencrypted" ) );
04011   if ( composer.hasKey( "crypto-warning-unsigned" ) )
04012     mWidget->mWarnUnsigned->setChecked( composer.readBoolEntry( "crypto-warning-unsigned" ) );
04013   if ( composer.hasKey( "crypto-warn-recv-not-in-cert" ) )
04014     mWidget->warnReceiverNotInCertificateCB->setChecked( composer.readBoolEntry( "crypto-warn-recv-not-in-cert" ) );
04015 
04016   if ( composer.hasKey( "crypto-warn-when-near-expire" ) )
04017     mWidget->warnGroupBox->setChecked( composer.readBoolEntry( "crypto-warn-when-near-expire" ) );
04018 
04019   if ( composer.hasKey( "crypto-warn-sign-key-near-expire-int" ) )
04020     mWidget->mWarnSignKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-key-near-expire-int" ) );
04021   if ( composer.hasKey( "crypto-warn-sign-chaincert-near-expire-int" ) )
04022     mWidget->mWarnSignChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int" ) );
04023   if ( composer.hasKey( "crypto-warn-sign-root-near-expire-int" ) )
04024     mWidget->mWarnSignRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-root-near-expire-int" ) );
04025 
04026   if ( composer.hasKey( "crypto-warn-encr-key-near-expire-int" ) )
04027     mWidget->mWarnEncrKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-key-near-expire-int" ) );
04028   if ( composer.hasKey( "crypto-warn-encr-chaincert-near-expire-int" ) )
04029     mWidget->mWarnEncrChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int" ) );
04030   if ( composer.hasKey( "crypto-warn-encr-root-near-expire-int" ) )
04031     mWidget->mWarnEncrRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-root-near-expire-int" ) );
04032 }
04033 
04034 void SecurityPage::WarningTab::save() {
04035   KConfigGroup composer( KMKernel::config(), "Composer" );
04036 
04037   composer.writeEntry( "crypto-warn-recv-not-in-cert", mWidget->warnReceiverNotInCertificateCB->isChecked() );
04038   composer.writeEntry( "crypto-warning-unencrypted", mWidget->warnUnencryptedCB->isChecked() );
04039   composer.writeEntry( "crypto-warning-unsigned", mWidget->mWarnUnsigned->isChecked() );
04040 
04041   composer.writeEntry( "crypto-warn-when-near-expire", mWidget->warnGroupBox->isChecked() );
04042   composer.writeEntry( "crypto-warn-sign-key-near-expire-int",
04043                        mWidget->mWarnSignKeyExpiresSB->value() );
04044   composer.writeEntry( "crypto-warn-sign-chaincert-near-expire-int",
04045                        mWidget->mWarnSignChainCertExpiresSB->value() );
04046   composer.writeEntry( "crypto-warn-sign-root-near-expire-int",
04047                        mWidget->mWarnSignRootCertExpiresSB->value() );
04048 
04049   composer.writeEntry( "crypto-warn-encr-key-near-expire-int",
04050                        mWidget->mWarnEncrKeyExpiresSB->value() );
04051   composer.writeEntry( "crypto-warn-encr-chaincert-near-expire-int",
04052                        mWidget->mWarnEncrChainCertExpiresSB->value() );
04053   composer.writeEntry( "crypto-warn-encr-root-near-expire-int",
04054                        mWidget->mWarnEncrRootCertExpiresSB->value() );
04055 }
04056 
04057 void SecurityPage::WarningTab::slotReenableAllWarningsClicked() {
04058   KMessageBox::enableAllMessages();
04059   mWidget->enableAllWarningsPB->setEnabled( false );
04060 }
04061 
04063 
04064 QString SecurityPage::SMimeTab::helpAnchor() const {
04065   return QString::fromLatin1("configure-security-smime-validation");
04066 }
04067 
04068 SecurityPageSMimeTab::SecurityPageSMimeTab( QWidget * parent, const char * name )
04069   : ConfigModuleTab( parent, name )
04070 {
04071   // the margins are inside mWidget itself
04072   QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 );
04073 
04074   mWidget = new SMimeConfiguration( this );
04075   vlay->addWidget( mWidget );
04076 
04077   // Button-group for exclusive radiobuttons
04078   QButtonGroup* bg = new QButtonGroup( mWidget );
04079   bg->hide();
04080   bg->insert( mWidget->CRLRB );
04081   bg->insert( mWidget->OCSPRB );
04082 
04083   // Settings for the keyrequester custom widget
04084   mWidget->OCSPResponderSignature->setAllowedKeys(
04085      Kleo::KeySelectionDialog::SMIMEKeys
04086      | Kleo::KeySelectionDialog::TrustedKeys
04087      | Kleo::KeySelectionDialog::ValidKeys
04088      | Kleo::KeySelectionDialog::SigningKeys
04089      | Kleo::KeySelectionDialog::PublicKeys );
04090   mWidget->OCSPResponderSignature->setMultipleKeysEnabled( false );
04091 
04092   mConfig = Kleo::CryptoBackendFactory::instance()->config();
04093 
04094   connect( mWidget->CRLRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04095   connect( mWidget->OCSPRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04096   connect( mWidget->OCSPResponderURL, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) );
04097   connect( mWidget->OCSPResponderSignature, SIGNAL( changed() ), this, SLOT( slotEmitChanged() ) );
04098   connect( mWidget->doNotCheckCertPolicyCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04099   connect( mWidget->neverConsultCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04100   connect( mWidget->fetchMissingCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04101 
04102   connect( mWidget->ignoreServiceURLCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04103   connect( mWidget->ignoreHTTPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04104   connect( mWidget->disableHTTPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04105   connect( mWidget->honorHTTPProxyRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04106   connect( mWidget->useCustomHTTPProxyRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04107   connect( mWidget->customHTTPProxy, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) );
04108   connect( mWidget->ignoreLDAPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04109   connect( mWidget->disableLDAPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) );
04110   connect( mWidget->customLDAPProxy, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) );
04111 
04112   connect( mWidget->disableHTTPCB, SIGNAL( toggled( bool ) ),
04113            this, SLOT( slotUpdateHTTPActions() ) );
04114   connect( mWidget->ignoreHTTPDPCB, SIGNAL( toggled( bool ) ),
04115            this, SLOT( slotUpdateHTTPActions() ) );
04116 
04117   // Button-group for exclusive radiobuttons
04118   QButtonGroup* bgHTTPProxy = new QButtonGroup( mWidget );
04119   bgHTTPProxy->hide();
04120   bgHTTPProxy->insert( mWidget->honorHTTPProxyRB );
04121   bgHTTPProxy->insert( mWidget->useCustomHTTPProxyRB );
04122 
04123   if ( !connectDCOPSignal( 0, "KPIM::CryptoConfig", "changed()",
04124                            "load()", false ) )
04125     kdError(5650) << "SecurityPageSMimeTab: connection to CryptoConfig's changed() failed" << endl;
04126 
04127 }
04128 
04129 SecurityPageSMimeTab::~SecurityPageSMimeTab()
04130 {
04131 }
04132 
04133 static void disableDirmngrWidget( QWidget* w ) {
04134   w->setEnabled( false );
04135   QWhatsThis::remove( w );
04136   QWhatsThis::add( w, i18n( "This option requires dirmngr >= 0.9.0" ) );
04137 }
04138 
04139 static void initializeDirmngrCheckbox( QCheckBox* cb, Kleo::CryptoConfigEntry* entry ) {
04140   if ( entry )
04141     cb->setChecked( entry->boolValue() );
04142   else
04143     disableDirmngrWidget( cb );
04144 }
04145 
04146 struct SMIMECryptoConfigEntries {
04147   SMIMECryptoConfigEntries( Kleo::CryptoConfig* config )
04148     : mConfig( config ) {
04149 
04150     // Checkboxes
04151     mCheckUsingOCSPConfigEntry = configEntry( "gpgsm", "Security", "enable-ocsp", Kleo::CryptoConfigEntry::ArgType_None, false );
04152     mEnableOCSPsendingConfigEntry = configEntry( "dirmngr", "OCSP", "allow-ocsp", Kleo::CryptoConfigEntry::ArgType_None, false );
04153     mDoNotCheckCertPolicyConfigEntry = configEntry( "gpgsm", "Security", "disable-policy-checks", Kleo::CryptoConfigEntry::ArgType_None, false );
04154     mNeverConsultConfigEntry = configEntry( "gpgsm", "Security", "disable-crl-checks", Kleo::CryptoConfigEntry::ArgType_None, false );
04155     mFetchMissingConfigEntry = configEntry( "gpgsm", "Security", "auto-issuer-key-retrieve", Kleo::CryptoConfigEntry::ArgType_None, false );
04156     // dirmngr-0.9.0 options
04157     mIgnoreServiceURLEntry = configEntry( "dirmngr", "OCSP", "ignore-ocsp-service-url", Kleo::CryptoConfigEntry::ArgType_None, false );
04158     mIgnoreHTTPDPEntry = configEntry( "dirmngr", "HTTP", "ignore-http-dp", Kleo::CryptoConfigEntry::ArgType_None, false );
04159     mDisableHTTPEntry = configEntry( "dirmngr", "HTTP", "disable-http", Kleo::CryptoConfigEntry::ArgType_None, false );
04160     mHonorHTTPProxy = configEntry( "dirmngr", "HTTP", "honor-http-proxy", Kleo::CryptoConfigEntry::ArgType_None, false );
04161 
04162     mIgnoreLDAPDPEntry = configEntry( "dirmngr", "LDAP", "ignore-ldap-dp", Kleo::CryptoConfigEntry::ArgType_None, false );
04163     mDisableLDAPEntry = configEntry( "dirmngr", "LDAP", "disable-ldap", Kleo::CryptoConfigEntry::ArgType_None, false );
04164     // Other widgets
04165     mOCSPResponderURLConfigEntry = configEntry( "dirmngr", "OCSP", "ocsp-responder", Kleo::CryptoConfigEntry::ArgType_String, false );
04166     mOCSPResponderSignature = configEntry( "dirmngr", "OCSP", "ocsp-signer", Kleo::CryptoConfigEntry::ArgType_String, false );
04167     mCustomHTTPProxy = configEntry( "dirmngr", "HTTP", "http-proxy", Kleo::CryptoConfigEntry::ArgType_String, false );
04168     mCustomLDAPProxy = configEntry( "dirmngr", "LDAP", "ldap-proxy", Kleo::CryptoConfigEntry::ArgType_String, false );
04169   }
04170 
04171   Kleo::CryptoConfigEntry* configEntry( const char* componentName,
04172                                         const char* groupName,
04173                                         const char* entryName,
04174                                         int argType,
04175                                         bool isList );
04176 
04177   // Checkboxes
04178   Kleo::CryptoConfigEntry* mCheckUsingOCSPConfigEntry;
04179   Kleo::CryptoConfigEntry* mEnableOCSPsendingConfigEntry;
04180   Kleo::CryptoConfigEntry* mDoNotCheckCertPolicyConfigEntry;
04181   Kleo::CryptoConfigEntry* mNeverConsultConfigEntry;
04182   Kleo::CryptoConfigEntry* mFetchMissingConfigEntry;
04183   Kleo::CryptoConfigEntry* mIgnoreServiceURLEntry;
04184   Kleo::CryptoConfigEntry* mIgnoreHTTPDPEntry;
04185   Kleo::CryptoConfigEntry* mDisableHTTPEntry;
04186   Kleo::CryptoConfigEntry* mHonorHTTPProxy;
04187   Kleo::CryptoConfigEntry* mIgnoreLDAPDPEntry;
04188   Kleo::CryptoConfigEntry* mDisableLDAPEntry;
04189   // Other widgets
04190   Kleo::CryptoConfigEntry* mOCSPResponderURLConfigEntry;
04191   Kleo::CryptoConfigEntry* mOCSPResponderSignature;
04192   Kleo::CryptoConfigEntry* mCustomHTTPProxy;
04193   Kleo::CryptoConfigEntry* mCustomLDAPProxy;
04194 
04195   Kleo::CryptoConfig* mConfig;
04196 };
04197 
04198 void SecurityPage::SMimeTab::doLoadOther() {
04199   if ( !mConfig ) {
04200     setEnabled( false );
04201     return;
04202   }
04203 
04204   // Force re-parsing gpgconf data, in case e.g. kleopatra or "configure backend" was used
04205   // (which ends up calling us via dcop)
04206   mConfig->clear();
04207 
04208   // Create config entries
04209   // Don't keep them around, they'll get deleted by clear(), which could be
04210   // done by the "configure backend" button even before we save().
04211   SMIMECryptoConfigEntries e( mConfig );
04212 
04213   // Initialize GUI items from the config entries
04214 
04215   if ( e.mCheckUsingOCSPConfigEntry ) {
04216     bool b = e.mCheckUsingOCSPConfigEntry->boolValue();
04217     mWidget->OCSPRB->setChecked( b );
04218     mWidget->CRLRB->setChecked( !b );
04219     mWidget->OCSPGroupBox->setEnabled( b );
04220   } else {
04221     mWidget->OCSPGroupBox->setEnabled( false );
04222   }
04223   if ( e.mDoNotCheckCertPolicyConfigEntry )
04224     mWidget->doNotCheckCertPolicyCB->setChecked( e.mDoNotCheckCertPolicyConfigEntry->boolValue() );
04225   if ( e.mNeverConsultConfigEntry )
04226     mWidget->neverConsultCB->setChecked( e.mNeverConsultConfigEntry->boolValue() );
04227   if ( e.mFetchMissingConfigEntry )
04228     mWidget->fetchMissingCB->setChecked( e.mFetchMissingConfigEntry->boolValue() );
04229 
04230   if ( e.mOCSPResponderURLConfigEntry )
04231     mWidget->OCSPResponderURL->setText( e.mOCSPResponderURLConfigEntry->stringValue() );
04232   if ( e.mOCSPResponderSignature ) {
04233     mWidget->OCSPResponderSignature->setFingerprint( e.mOCSPResponderSignature->stringValue() );
04234   }
04235 
04236   // dirmngr-0.9.0 options
04237   initializeDirmngrCheckbox( mWidget->ignoreServiceURLCB, e.mIgnoreServiceURLEntry );
04238   initializeDirmngrCheckbox( mWidget->ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry );
04239   initializeDirmngrCheckbox( mWidget->disableHTTPCB, e.mDisableHTTPEntry );
04240   initializeDirmngrCheckbox( mWidget->ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry );
04241   initializeDirmngrCheckbox( mWidget->disableLDAPCB, e.mDisableLDAPEntry );
04242   if ( e.mCustomHTTPProxy ) {
04243     QString systemProxy = QString::fromLocal8Bit( getenv( "http_proxy" ) );
04244     if ( systemProxy.isEmpty() )
04245       systemProxy = i18n( "no proxy" );
04246     mWidget->systemHTTPProxy->setText( i18n( "(Current system setting: %1)" ).arg( systemProxy ) );
04247     bool honor = e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue();
04248     mWidget->honorHTTPProxyRB->setChecked( honor );
04249     mWidget->useCustomHTTPProxyRB->setChecked( !honor );
04250     mWidget->customHTTPProxy->setText( e.mCustomHTTPProxy->stringValue() );
04251   } else {
04252     disableDirmngrWidget( mWidget->honorHTTPProxyRB );
04253     disableDirmngrWidget( mWidget->useCustomHTTPProxyRB );
04254     disableDirmngrWidget( mWidget->systemHTTPProxy );
04255     disableDirmngrWidget( mWidget->customHTTPProxy );
04256   }
04257   if ( e.mCustomLDAPProxy )
04258     mWidget->customLDAPProxy->setText( e.mCustomLDAPProxy->stringValue() );
04259   else {
04260     disableDirmngrWidget( mWidget->customLDAPProxy );
04261     disableDirmngrWidget( mWidget->customLDAPLabel );
04262   }
04263   slotUpdateHTTPActions();
04264 }
04265 
04266 void SecurityPage::SMimeTab::slotUpdateHTTPActions() {
04267   mWidget->ignoreHTTPDPCB->setEnabled( !mWidget->disableHTTPCB->isChecked() );
04268 
04269   // The proxy settings only make sense when "Ignore HTTP CRL DPs of certificate" is checked.
04270   bool enableProxySettings = !mWidget->disableHTTPCB->isChecked()
04271                           && mWidget->ignoreHTTPDPCB->isChecked();
04272   mWidget->systemHTTPProxy->setEnabled( enableProxySettings );
04273   mWidget->useCustomHTTPProxyRB->setEnabled( enableProxySettings );
04274   mWidget->honorHTTPProxyRB->setEnabled( enableProxySettings );
04275   mWidget->customHTTPProxy->setEnabled( enableProxySettings );
04276 }
04277 
04278 void SecurityPage::SMimeTab::installProfile( KConfig * ) {
04279 }
04280 
04281 static void saveCheckBoxToKleoEntry( QCheckBox* cb, Kleo::CryptoConfigEntry* entry ) {
04282   const bool b = cb->isChecked();
04283   if ( entry && entry->boolValue() != b )
04284     entry->setBoolValue( b );
04285 }
04286 
04287 void SecurityPage::SMimeTab::save() {
04288   if ( !mConfig ) {
04289     return;
04290   }
04291   // Create config entries
04292   // Don't keep them around, they'll get deleted by clear(), which could be done by the
04293   // "configure backend" button.
04294   SMIMECryptoConfigEntries e( mConfig );
04295 
04296   bool b = mWidget->OCSPRB->isChecked();
04297   if ( e.mCheckUsingOCSPConfigEntry && e.mCheckUsingOCSPConfigEntry->boolValue() != b )
04298     e.mCheckUsingOCSPConfigEntry->setBoolValue( b );
04299   // Set allow-ocsp together with enable-ocsp
04300   if ( e.mEnableOCSPsendingConfigEntry && e.mEnableOCSPsendingConfigEntry->boolValue() != b )
04301     e.mEnableOCSPsendingConfigEntry->setBoolValue( b );
04302 
04303   saveCheckBoxToKleoEntry( mWidget->doNotCheckCertPolicyCB, e.mDoNotCheckCertPolicyConfigEntry );
04304   saveCheckBoxToKleoEntry( mWidget->neverConsultCB, e.mNeverConsultConfigEntry );
04305   saveCheckBoxToKleoEntry( mWidget->fetchMissingCB, e.mFetchMissingConfigEntry );
04306 
04307   QString txt = mWidget->OCSPResponderURL->text();
04308   if ( e.mOCSPResponderURLConfigEntry && e.mOCSPResponderURLConfigEntry->stringValue() != txt )
04309     e.mOCSPResponderURLConfigEntry->setStringValue( txt );
04310 
04311   txt = mWidget->OCSPResponderSignature->fingerprint();
04312   if ( e.mOCSPResponderSignature && e.mOCSPResponderSignature->stringValue() != txt ) {
04313     e.mOCSPResponderSignature->setStringValue( txt );
04314   }
04315 
04316   //dirmngr-0.9.0 options
04317   saveCheckBoxToKleoEntry( mWidget->ignoreServiceURLCB, e.mIgnoreServiceURLEntry );
04318   saveCheckBoxToKleoEntry( mWidget->ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry );
04319   saveCheckBoxToKleoEntry( mWidget->disableHTTPCB, e.mDisableHTTPEntry );
04320   saveCheckBoxToKleoEntry( mWidget->ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry );
04321   saveCheckBoxToKleoEntry( mWidget->disableLDAPCB, e.mDisableLDAPEntry );
04322   if ( e.mCustomHTTPProxy ) {
04323     const bool honor = mWidget->honorHTTPProxyRB->isChecked();
04324     if ( e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue() != honor )
04325         e.mHonorHTTPProxy->setBoolValue( honor );
04326 
04327     QString chosenProxy = mWidget->customHTTPProxy->text();
04328     if ( chosenProxy != e.mCustomHTTPProxy->stringValue() )
04329       e.mCustomHTTPProxy->setStringValue( chosenProxy );
04330   }
04331   txt = mWidget->customLDAPProxy->text();
04332   if ( e.mCustomLDAPProxy && e.mCustomLDAPProxy->stringValue() != txt )
04333     e.mCustomLDAPProxy->setStringValue( mWidget->customLDAPProxy->text() );
04334 
04335   mConfig->sync( true );
04336 }
04337 
04338 bool SecurityPageSMimeTab::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData)
04339 {
04340     if ( fun == "load()" ) {
04341         replyType = "void";
04342         load();
04343     } else {
04344         return DCOPObject::process( fun, data, replyType, replyData );
04345     }
04346     return true;
04347 }
04348 
04349 QCStringList SecurityPageSMimeTab::interfaces()
04350 {
04351   QCStringList ifaces = DCOPObject::interfaces();
04352   ifaces += "SecurityPageSMimeTab";
04353   return ifaces;
04354 }
04355 
04356 QCStringList SecurityPageSMimeTab::functions()
04357 {
04358   // Hide our slot, just because it's simpler to do so.
04359   return DCOPObject::functions();
04360 }
04361 
04362 Kleo::CryptoConfigEntry* SMIMECryptoConfigEntries::configEntry( const char* componentName,
04363                                                                 const char* groupName,
04364                                                                 const char* entryName,
04365                                                                 int /*Kleo::CryptoConfigEntry::ArgType*/ argType,
04366                                                                 bool isList )
04367 {
04368     Kleo::CryptoConfigEntry* entry = mConfig->entry( componentName, groupName, entryName );
04369     if ( !entry ) {
04370         kdWarning(5006) << QString( "Backend error: gpgconf doesn't seem to know the entry for %1/%2/%3" ).arg( componentName, groupName, entryName ) << endl;
04371         return 0;
04372     }
04373     if( entry->argType() != argType || entry->isList() != isList ) {
04374         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;
04375         return 0;
04376     }
04377     return entry;
04378 }
04379 
04381 
04382 QString SecurityPage::CryptPlugTab::helpAnchor() const {
04383   return QString::fromLatin1("configure-security-crypto-backends");
04384 }
04385 
04386 SecurityPageCryptPlugTab::SecurityPageCryptPlugTab( QWidget * parent, const char * name )
04387   : ConfigModuleTab( parent, name )
04388 {
04389   QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
04390 
04391   mBackendConfig = Kleo::CryptoBackendFactory::instance()->configWidget( this, "mBackendConfig" );
04392   connect( mBackendConfig, SIGNAL( changed( bool ) ), this, SIGNAL( changed( bool ) ) );
04393 
04394   vlay->addWidget( mBackendConfig );
04395 }
04396 
04397 SecurityPageCryptPlugTab::~SecurityPageCryptPlugTab()
04398 {
04399 
04400 }
04401 
04402 void SecurityPage::CryptPlugTab::doLoadOther() {
04403   mBackendConfig->load();
04404 }
04405 
04406 void SecurityPage::CryptPlugTab::save() {
04407   mBackendConfig->save();
04408 }
04409 
04410 // *************************************************************
04411 // *                                                           *
04412 // *                        MiscPage                           *
04413 // *                                                           *
04414 // *************************************************************
04415 QString MiscPage::helpAnchor() const {
04416   return QString::fromLatin1("configure-misc");
04417 }
04418 
04419 MiscPage::MiscPage( QWidget * parent, const char * name )
04420   : ConfigModuleWithTabs( parent, name )
04421 {
04422   mFolderTab = new FolderTab();
04423   addTab( mFolderTab, i18n("&Folders") );
04424 
04425   mGroupwareTab = new GroupwareTab();
04426   addTab( mGroupwareTab, i18n("&Groupware") );
04427   load();
04428 }
04429 
04430 QString MiscPage::FolderTab::helpAnchor() const {
04431   return QString::fromLatin1("configure-misc-folders");
04432 }
04433 
04434 MiscPageFolderTab::MiscPageFolderTab( QWidget * parent, const char * name )
04435   : ConfigModuleTab( parent, name )
04436 {
04437   // temp. vars:
04438   QVBoxLayout *vlay;
04439   QHBoxLayout *hlay;
04440   QLabel      *label;
04441 
04442   vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
04443 
04444   // "confirm before emptying folder" check box: stretch 0
04445   mEmptyFolderConfirmCheck =
04446     new QCheckBox( i18n("Corresponds to Folder->Move All Messages to Trash",
04447                         "Ask for co&nfirmation before moving all messages to "
04448                         "trash"),
04449                    this );
04450   vlay->addWidget( mEmptyFolderConfirmCheck );
04451   connect( mEmptyFolderConfirmCheck, SIGNAL( stateChanged( int ) ),
04452            this, SLOT( slotEmitChanged( void ) ) );
04453   mExcludeImportantFromExpiry =
04454     new QCheckBox( i18n("E&xclude important messages from expiry"), this );
04455   vlay->addWidget( mExcludeImportantFromExpiry );
04456   connect( mExcludeImportantFromExpiry, SIGNAL( stateChanged( int ) ),
04457            this, SLOT( slotEmitChanged( void ) ) );
04458 
04459   // "when trying to find unread messages" combo + label: stretch 0
04460   hlay = new QHBoxLayout( vlay ); // inherits spacing
04461   mLoopOnGotoUnread = new QComboBox( false, this );
04462   label = new QLabel( mLoopOnGotoUnread,
04463            i18n("to be continued with \"do not loop\", \"loop in current folder\", "
04464                 "and \"loop in all folders\".",
04465                 "When trying to find unread messages:"), this );
04466   mLoopOnGotoUnread->insertStringList( QStringList()
04467       << i18n("continuation of \"When trying to find unread messages:\"",
04468               "Do not Loop")
04469       << i18n("continuation of \"When trying to find unread messages:\"",
04470               "Loop in Current Folder")
04471       << i18n("continuation of \"When trying to find unread messages:\"",
04472               "Loop in All Folders"));
04473   hlay->addWidget( label );
04474   hlay->addWidget( mLoopOnGotoUnread, 1 );
04475   connect( mLoopOnGotoUnread, SIGNAL( activated( int ) ),
04476            this, SLOT( slotEmitChanged( void ) ) );
04477 
04478   // when entering a folder
04479   hlay = new QHBoxLayout( vlay ); // inherits spacing
04480   mActionEnterFolder = new QComboBox( false, this );
04481   label = new QLabel( mActionEnterFolder,
04482            i18n("to be continued with \"jump to first new message\", "
04483                 "\"jump to first unread or new message\","
04484                 "and \"jump to last selected message\".",
04485                 "When entering a folder:"), this );
04486   mActionEnterFolder->insertStringList( QStringList()
04487       << i18n("continuation of \"When entering a folder:\"",
04488               "Jump to First New Message")
04489       << i18n("continuation of \"When entering a folder:\"",
04490               "Jump to First Unread or New Message")
04491       << i18n("continuation of \"When entering a folder:\"",
04492               "Jump to Last Selected Message"));
04493   hlay->addWidget( label );
04494   hlay->addWidget( mActionEnterFolder, 1 );
04495   connect( mActionEnterFolder, SIGNAL( activated( int ) ),
04496            this, SLOT( slotEmitChanged( void ) ) );
04497 
04498   hlay = new QHBoxLayout( vlay ); // inherits spacing
04499   mDelayedMarkAsRead = new QCheckBox( i18n("Mar&k selected message as read after"), this );
04500   hlay->addWidget( mDelayedMarkAsRead );
04501   mDelayedMarkTime = new KIntSpinBox( 0 /*min*/, 60 /*max*/, 1/*step*/,
04502                                       0 /*init*/, 10 /*base*/, this);
04503   mDelayedMarkTime->setSuffix( i18n(" sec") );
04504   mDelayedMarkTime->setEnabled( false ); // since mDelayedMarkAsREad is off
04505   hlay->addWidget( mDelayedMarkTime );
04506   hlay->addStretch( 1 );
04507   connect( mDelayedMarkTime, SIGNAL( valueChanged( int ) ),
04508            this, SLOT( slotEmitChanged( void ) ) );
04509   connect( mDelayedMarkAsRead, SIGNAL(toggled(bool)),
04510            mDelayedMarkTime, SLOT(setEnabled(bool)));
04511   connect( mDelayedMarkAsRead, SIGNAL(toggled(bool)),
04512            this , SLOT(slotEmitChanged( void )));
04513 
04514   // "show popup after Drag'n'Drop" checkbox: stretch 0
04515   mShowPopupAfterDnD =
04516     new QCheckBox( i18n("Ask for action after &dragging messages to another folder"), this );
04517   vlay->addWidget( mShowPopupAfterDnD );
04518   connect( mShowPopupAfterDnD, SIGNAL( stateChanged( int ) ),
04519            this, SLOT( slotEmitChanged( void ) ) );
04520 
04521   // "default mailbox format" combo + label: stretch 0
04522   hlay = new QHBoxLayout( vlay ); // inherits spacing
04523   mMailboxPrefCombo = new QComboBox( false, this );
04524   label = new QLabel( mMailboxPrefCombo,
04525                       i18n("to be continued with \"flat files\" and "
04526                            "\"directories\", resp.",
04527                            "By default, &message folders on disk are:"), this );
04528   mMailboxPrefCombo->insertStringList( QStringList()
04529           << i18n("continuation of \"By default, &message folders on disk are\"",
04530                   "Flat Files (\"mbox\" format)")
04531           << i18n("continuation of \"By default, &message folders on disk are\"",
04532                   "Directories (\"maildir\" format)") );
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   hlay->addWidget( label );
04551   hlay->addWidget( mMailboxPrefCombo, 1 );
04552   connect( mMailboxPrefCombo, SIGNAL( activated( int ) ),
04553            this, SLOT( slotEmitChanged( void ) ) );
04554 
04555   // "On startup..." option:
04556   hlay = new QHBoxLayout( vlay ); // inherits spacing
04557   mOnStartupOpenFolder = new FolderRequester( this,
04558       kmkernel->getKMMainWidget()->folderTree() );
04559   label = new QLabel( mOnStartupOpenFolder,
04560                       i18n("Open this folder on startup:"), this );
04561   hlay->addWidget( label );
04562   hlay->addWidget( mOnStartupOpenFolder, 1 );
04563   connect( mOnStartupOpenFolder, SIGNAL( folderChanged( KMFolder* ) ),
04564            this, SLOT( slotEmitChanged( void ) ) );
04565 
04566   // "Empty &trash on program exit" option:
04567   hlay = new QHBoxLayout( vlay ); // inherits spacing
04568   mEmptyTrashCheck = new QCheckBox( i18n("Empty local &trash folder on program exit"),
04569                                     this );
04570   hlay->addWidget( mEmptyTrashCheck );
04571   connect( mEmptyTrashCheck, SIGNAL( stateChanged( int ) ),
04572            this, SLOT( slotEmitChanged( void ) ) );
04573 
04574 #ifdef HAVE_INDEXLIB
04575   // indexing enabled option:
04576   mIndexingEnabled = new QCheckBox( i18n("Enable full text &indexing"), this );
04577   vlay->addWidget( mIndexingEnabled );
04578   connect( mIndexingEnabled, SIGNAL( stateChanged( int ) ),
04579            this, SLOT( slotEmitChanged( void ) ) );
04580 #endif
04581 
04582   // "Quota Units"
04583   hlay = new QHBoxLayout( vlay ); // inherits spacing
04584   mQuotaCmbBox = new QComboBox( false, this );
04585   label = new QLabel( mQuotaCmbBox,
04586                       i18n("Quota units: "), this );
04587   mQuotaCmbBox->insertStringList( QStringList()
04588                    << i18n("KB")
04589                    << i18n("MB")
04590                    << i18n("GB") );
04591   hlay->addWidget( label );
04592   hlay->addWidget( mQuotaCmbBox, 1 );
04593   connect( mQuotaCmbBox, SIGNAL( activated( int )  ), this, SLOT( slotEmitChanged( void ) ) );
04594 
04595   vlay->addStretch( 1 );
04596 
04597   // @TODO: Till, move into .kcgc file
04598   msg = i18n( "what's this help",
04599             "<qt><p>When jumping to the next unread message, it may occur "
04600             "that no more unread messages are below the current message.</p>"
04601             "<p><b>Do not loop:</b> The search will stop at the last message in "
04602             "the current folder.</p>"
04603             "<p><b>Loop in current folder:</b> The search will continue at the "
04604             "top of the message list, but not go to another folder.</p>"
04605             "<p><b>Loop in all folders:</b> The search will continue at the top of "
04606             "the message list. If no unread messages are found it will then continue "
04607             "to the next folder.</p>"
04608             "<p>Similarly, when searching for the previous unread message, "
04609             "the search will start from the bottom of the message list and continue to "
04610             "the previous folder depending on which option is selected.</p></qt>" );
04611   QWhatsThis::add( mLoopOnGotoUnread, msg );
04612 
04613 #ifdef HAVE_INDEXLIB
04614  // this is probably overly pessimistic
04615   msg = i18n( "what's this help",
04616           "<qt><p>Full text indexing allows very fast searches on the content "
04617           "of your messages. When enabled, the search dialog will work very fast. "
04618           "Also, the search tool bar will select messages based on content.</p>"
04619           "<p>It takes up a certain amount of disk space "
04620           "(about half the disk space for the messages).</p>"
04621           "<p>After enabling, the index will need to be built, but you can continue to use KMail "
04622           "while this operation is running.</p>"
04623           "</qt>"
04624         );
04625 
04626   QWhatsThis::add( mIndexingEnabled, msg );
04627 #endif
04628 }
04629 
04630 void MiscPage::FolderTab::doLoadFromGlobalSettings() {
04631   mExcludeImportantFromExpiry->setChecked( GlobalSettings::self()->excludeImportantMailFromExpiry() );
04632   // default = "Loop in current folder"
04633   mLoopOnGotoUnread->setCurrentItem( GlobalSettings::self()->loopOnGotoUnread() );
04634   mActionEnterFolder->setCurrentItem( GlobalSettings::self()->actionEnterFolder() );
04635   mDelayedMarkAsRead->setChecked( GlobalSettings::self()->delayedMarkAsRead() );
04636   mDelayedMarkTime->setValue( GlobalSettings::self()->delayedMarkTime() );
04637   mShowPopupAfterDnD->setChecked( GlobalSettings::self()->showPopupAfterDnD() );
04638   mQuotaCmbBox->setCurrentItem( GlobalSettings::self()->quotaUnit() );
04639 }
04640 
04641 void MiscPage::FolderTab::doLoadOther() {
04642   KConfigGroup general( KMKernel::config(), "General" );
04643 
04644   mEmptyTrashCheck->setChecked( general.readBoolEntry( "empty-trash-on-exit", true ) );
04645   mOnStartupOpenFolder->setFolder( general.readEntry( "startupFolder",
04646                                                   kmkernel->inboxFolder()->idString() ) );
04647   mEmptyFolderConfirmCheck->setChecked( general.readBoolEntry( "confirm-before-empty", true ) );
04648 
04649   int num = general.readNumEntry("default-mailbox-format", 1 );
04650   if ( num < 0 || num > 1 ) num = 1;
04651   mMailboxPrefCombo->setCurrentItem( num );
04652 
04653 #ifdef HAVE_INDEXLIB
04654   mIndexingEnabled->setChecked( kmkernel->msgIndex() && kmkernel->msgIndex()->isEnabled() );
04655 #endif
04656 }
04657 
04658 void MiscPage::FolderTab::save() {
04659   KConfigGroup general( KMKernel::config(), "General" );
04660 
04661   general.writeEntry( "empty-trash-on-exit", mEmptyTrashCheck->isChecked() );
04662   general.writeEntry( "confirm-before-empty", mEmptyFolderConfirmCheck->isChecked() );
04663   general.writeEntry( "default-mailbox-format", mMailboxPrefCombo->currentItem() );
04664   general.writeEntry( "startupFolder", mOnStartupOpenFolder->folder() ?
04665                                   mOnStartupOpenFolder->folder()->idString() : QString::null );
04666 
04667   GlobalSettings::self()->setDelayedMarkAsRead( mDelayedMarkAsRead->isChecked() );
04668   GlobalSettings::self()->setDelayedMarkTime( mDelayedMarkTime->value() );
04669   GlobalSettings::self()->setActionEnterFolder( mActionEnterFolder->currentItem() );
04670   GlobalSettings::self()->setLoopOnGotoUnread( mLoopOnGotoUnread->currentItem() );
04671   GlobalSettings::self()->setShowPopupAfterDnD( mShowPopupAfterDnD->isChecked() );
04672   GlobalSettings::self()->setExcludeImportantMailFromExpiry(
04673         mExcludeImportantFromExpiry->isChecked() );
04674   GlobalSettings::self()->setQuotaUnit( mQuotaCmbBox->currentItem() );
04675 #ifdef HAVE_INDEXLIB
04676   if ( kmkernel->msgIndex() ) kmkernel->msgIndex()->setEnabled( mIndexingEnabled->isChecked() );
04677 #endif
04678 }
04679 
04680 QString MiscPage::GroupwareTab::helpAnchor() const {
04681   return QString::fromLatin1("configure-misc-groupware");
04682 }
04683 
04684 MiscPageGroupwareTab::MiscPageGroupwareTab( QWidget* parent, const char* name )
04685   : ConfigModuleTab( parent, name )
04686 {
04687   QBoxLayout* vlay = new QVBoxLayout( this, KDialog::marginHint(),
04688                                       KDialog::spacingHint() );
04689   vlay->setAutoAdd( true );
04690 
04691   // IMAP resource setup
04692   QVGroupBox* b1 = new QVGroupBox( i18n("&IMAP Resource Folder Options"),
04693                                    this );
04694 
04695   mEnableImapResCB =
04696     new QCheckBox( i18n("&Enable IMAP resource functionality"), b1 );
04697   QToolTip::add( mEnableImapResCB,  i18n( "This enables the IMAP storage for "
04698                                           "the Kontact applications" ) );
04699   QWhatsThis::add( mEnableImapResCB,
04700         i18n( GlobalSettings::self()->theIMAPResourceEnabledItem()->whatsThis().utf8() ) );
04701   connect( mEnableImapResCB, SIGNAL( stateChanged( int ) ),
04702            this, SLOT( slotEmitChanged( void ) ) );
04703 
04704   mBox = new QWidget( b1 );
04705   QGridLayout* grid = new QGridLayout( mBox, 4, 2, 0, KDialog::spacingHint() );
04706   grid->setColStretch( 1, 1 );
04707   connect( mEnableImapResCB, SIGNAL( toggled(bool) ),
04708            mBox, SLOT( setEnabled(bool) ) );
04709 
04710   QLabel* storageFormatLA = new QLabel( i18n("&Format used for the groupware folders:"),
04711                                         mBox );
04712   QString toolTip = i18n( "Choose the format to use to store the contents of the groupware folders." );
04713   QString whatsThis = i18n( GlobalSettings::self()
04714         ->theIMAPResourceStorageFormatItem()->whatsThis().utf8() );
04715   grid->addWidget( storageFormatLA, 0, 0 );
04716   QToolTip::add( storageFormatLA, toolTip );
04717   QWhatsThis::add( storageFormatLA, whatsThis );
04718   mStorageFormatCombo = new QComboBox( false, mBox );
04719   storageFormatLA->setBuddy( mStorageFormatCombo );
04720   QStringList formatLst;
04721   formatLst << i18n("Standard (Ical / Vcard)") << i18n("Kolab (XML)");
04722   mStorageFormatCombo->insertStringList( formatLst );
04723   grid->addWidget( mStorageFormatCombo, 0, 1 );
04724   QToolTip::add( mStorageFormatCombo, toolTip );
04725   QWhatsThis::add( mStorageFormatCombo, whatsThis );
04726   connect( mStorageFormatCombo, SIGNAL( activated( int ) ),
04727            this, SLOT( slotStorageFormatChanged( int ) ) );
04728 
04729   QLabel* languageLA = new QLabel( i18n("&Language of the groupware folders:"),
04730                                    mBox );
04731 
04732   toolTip = i18n( "Set the language of the folder names" );
04733   whatsThis = i18n( GlobalSettings::self()
04734         ->theIMAPResourceFolderLanguageItem()->whatsThis().utf8() );
04735   grid->addWidget( languageLA, 1, 0 );
04736   QToolTip::add( languageLA, toolTip );
04737   QWhatsThis::add( languageLA, whatsThis );
04738   mLanguageCombo = new QComboBox( false, mBox );
04739   languageLA->setBuddy( mLanguageCombo );
04740   QStringList lst;
04741   lst << i18n("English") << i18n("German") << i18n("French") << i18n("Dutch");
04742   mLanguageCombo->insertStringList( lst );
04743   grid->addWidget( mLanguageCombo, 1, 1 );
04744   QToolTip::add( mLanguageCombo, toolTip );
04745   QWhatsThis::add( mLanguageCombo, whatsThis );
04746   connect( mLanguageCombo, SIGNAL( activated( int ) ),
04747            this, SLOT( slotEmitChanged( void ) ) );
04748 
04749   mFolderComboLabel = new QLabel( mBox ); // text depends on storage format
04750   toolTip = i18n( "Set the parent of the resource folders" );
04751   whatsThis = i18n( GlobalSettings::self()->theIMAPResourceFolderParentItem()->whatsThis().utf8() );
04752   QToolTip::add( mFolderComboLabel, toolTip );
04753   QWhatsThis::add( mFolderComboLabel, whatsThis );
04754   grid->addWidget( mFolderComboLabel, 2, 0 );
04755 
04756   mFolderComboStack = new QWidgetStack( mBox );
04757   grid->addWidget( mFolderComboStack, 2, 1 );
04758 
04759   // First possibility in the widgetstack: a combo showing the list of all folders
04760   // This is used with the ical/vcard storage
04761   mFolderCombo = new FolderRequester( mBox,
04762       kmkernel->getKMMainWidget()->folderTree() );
04763   mFolderComboStack->addWidget( mFolderCombo, 0 );
04764   QToolTip::add( mFolderCombo, toolTip );
04765   QWhatsThis::add( mFolderCombo, whatsThis );
04766   connect( mFolderCombo, SIGNAL( folderChanged( KMFolder* ) ),
04767            this, SLOT( slotEmitChanged() ) );
04768 
04769   // Second possibility in the widgetstack: a combo showing the list of accounts
04770   // This is used with the kolab xml storage since the groupware folders
04771   // are always under the inbox.
04772   mAccountCombo = new KMail::AccountComboBox( mBox );
04773   mFolderComboStack->addWidget( mAccountCombo, 1 );
04774   QToolTip::add( mAccountCombo, toolTip );
04775   QWhatsThis::add( mAccountCombo, whatsThis );
04776   connect( mAccountCombo, SIGNAL( activated( int ) ),
04777            this, SLOT( slotEmitChanged() ) );
04778 
04779   mHideGroupwareFolders = new QCheckBox( i18n( "&Hide groupware folders" ),
04780                                          mBox, "HideGroupwareFoldersBox" );
04781   grid->addMultiCellWidget( mHideGroupwareFolders, 3, 3, 0, 0 );
04782   QToolTip::add( mHideGroupwareFolders,
04783                  i18n( "When this is checked, you will not see the IMAP "
04784                        "resource folders in the folder tree." ) );
04785   QWhatsThis::add( mHideGroupwareFolders, i18n( GlobalSettings::self()
04786            ->hideGroupwareFoldersItem()->whatsThis().utf8() ) );
04787   connect( mHideGroupwareFolders, SIGNAL( toggled( bool ) ),
04788            this, SLOT( slotEmitChanged() ) );
04789 
04790   mOnlyShowGroupwareFolders = new QCheckBox( i18n( "&Only show groupware folders for this account" ),
04791                                          mBox, "OnlyGroupwareFoldersBox" );
04792   grid->addMultiCellWidget( mOnlyShowGroupwareFolders, 3, 3, 1, 1 );
04793   QToolTip::add( mOnlyShowGroupwareFolders,
04794                  i18n( "When this is checked, you will not see normal  "
04795                        "mail folders in the folder tree for the account "
04796                        "configured for groupware." ) );
04797   QWhatsThis::add( mOnlyShowGroupwareFolders, i18n( GlobalSettings::self()
04798            ->showOnlyGroupwareFoldersForGroupwareAccountItem()->whatsThis().utf8() ) );
04799   connect( mOnlyShowGroupwareFolders, SIGNAL( toggled( bool ) ),
04800            this, SLOT( slotEmitChanged() ) );
04801 
04802   // Groupware functionality compatibility setup
04803   b1 = new QVGroupBox( i18n("Groupware Compatibility && Legacy Options"), this );
04804 
04805   gBox = new QVBox( b1 );
04806 #if 0
04807   // Currently believed to be disused.
04808   mEnableGwCB = new QCheckBox( i18n("&Enable groupware functionality"), b1 );
04809   gBox->setSpacing( KDialog::spacingHint() );
04810   connect( mEnableGwCB, SIGNAL( toggled(bool) ),
04811            gBox, SLOT( setEnabled(bool) ) );
04812   connect( mEnableGwCB, SIGNAL( stateChanged( int ) ),
04813            this, SLOT( slotEmitChanged( void ) ) );
04814 #endif
04815   mEnableGwCB = 0;
04816   mLegacyMangleFromTo = new QCheckBox( i18n( "Mangle From:/To: headers in replies to invitations" ), gBox );
04817   QToolTip::add( mLegacyMangleFromTo, i18n( "Turn this option on in order to make Outlook(tm) understand your answers to invitation replies" ) );
04818   QWhatsThis::add( mLegacyMangleFromTo, i18n( GlobalSettings::self()->
04819            legacyMangleFromToHeadersItem()->whatsThis().utf8() ) );
04820   connect( mLegacyMangleFromTo, SIGNAL( stateChanged( int ) ),
04821            this, SLOT( slotEmitChanged( void ) ) );
04822   mLegacyBodyInvites = new QCheckBox( i18n( "Send invitations in the mail body" ), gBox );
04823   QToolTip::add( mLegacyBodyInvites, i18n( "Turn this option on in order to make Outlook(tm) understand your answers to invitations" ) );
04824   QWhatsThis::add( mLegacyMangleFromTo, i18n( GlobalSettings::self()->
04825            legacyBodyInvitesItem()->whatsThis().utf8() ) );
04826   connect( mLegacyBodyInvites, SIGNAL( toggled( bool ) ),
04827            this, SLOT( slotLegacyBodyInvitesToggled( bool ) ) );
04828   connect( mLegacyBodyInvites, SIGNAL( stateChanged( int ) ),
04829            this, SLOT( slotEmitChanged( void ) ) );
04830   mAutomaticSending = new QCheckBox( i18n( "Automatic invitation sending" ), gBox );
04831   QToolTip::add( mAutomaticSending, i18n( "When this is on, the user will not see the mail composer window. Invitation mails are sent automatically" ) );
04832   QWhatsThis::add( mAutomaticSending, i18n( GlobalSettings::self()->
04833            automaticSendingItem()->whatsThis().utf8() ) );
04834   connect( mAutomaticSending, SIGNAL( stateChanged( int ) ),
04835            this, SLOT( slotEmitChanged( void ) ) );
04836 
04837   // Open space padding at the end
04838   new QLabel( this );
04839 }
04840 
04841 void MiscPageGroupwareTab::slotLegacyBodyInvitesToggled( bool on )
04842 {
04843   if ( on ) {
04844     QString txt = i18n( "<qt>Invitations are normally sent as attachments to "
04845                         "a mail. This switch changes the invitation mails to "
04846                         "be sent in the text of the mail instead; this is "
04847                         "necessary to send invitations and replies to "
04848                         "Microsoft Outlook.<br>But, when you do this, you no "
04849                         "longer get descriptive text that mail programs "
04850                         "can read; so, to people who have email programs "
04851                         "that do not understand the invitations, the "
04852                         "resulting messages look very odd.<br>People that have email "
04853                         "programs that do understand invitations will still "
04854                         "be able to work with this.</qt>" );
04855     KMessageBox::information( this, txt, QString::null,
04856                               "LegacyBodyInvitesWarning" );
04857   }
04858   // Invitations in the body are autosent in any case (no point in editing raw ICAL)
04859   // So the autosend option is only available if invitations are sent as attachment.
04860   mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() );
04861 }
04862 
04863 void MiscPage::GroupwareTab::doLoadFromGlobalSettings() {
04864   // Read the groupware config
04865   if ( mEnableGwCB ) {
04866     mEnableGwCB->setChecked( GlobalSettings::self()->groupwareEnabled() );
04867     gBox->setEnabled( mEnableGwCB->isChecked() );
04868   }
04869   mLegacyMangleFromTo->setChecked( GlobalSettings::self()->legacyMangleFromToHeaders() );
04870   mLegacyBodyInvites->blockSignals( true );
04871   mLegacyBodyInvites->setChecked( GlobalSettings::self()->legacyBodyInvites() );
04872   mLegacyBodyInvites->blockSignals( false );
04873   mAutomaticSending->setChecked( GlobalSettings::self()->automaticSending() );
04874   mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() );
04875 
04876   // Read the IMAP resource config
04877   mEnableImapResCB->setChecked( GlobalSettings::self()->theIMAPResourceEnabled() );
04878   mBox->setEnabled( mEnableImapResCB->isChecked() );
04879 
04880   mHideGroupwareFolders->setChecked( GlobalSettings::self()->hideGroupwareFolders() );
04881   int i = GlobalSettings::self()->theIMAPResourceFolderLanguage();
04882   mLanguageCombo->setCurrentItem(i);
04883   i = GlobalSettings::self()->theIMAPResourceStorageFormat();
04884   mStorageFormatCombo->setCurrentItem(i);
04885   slotStorageFormatChanged( i );
04886   mOnlyShowGroupwareFolders->setChecked( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount() );
04887 
04888   QString folderId( GlobalSettings::self()->theIMAPResourceFolderParent() );
04889   if( !folderId.isNull() && kmkernel->findFolderById( folderId ) ) {
04890     mFolderCombo->setFolder( folderId );
04891   } else {
04892     // Folder was deleted, we have to choose a new one
04893     mFolderCombo->setFolder( i18n( "<Choose a Folder>" ) );
04894   }
04895 
04896   KMAccount* selectedAccount = 0;
04897   int accountId = GlobalSettings::self()->theIMAPResourceAccount();
04898   if ( accountId )
04899     selectedAccount = kmkernel->acctMgr()->find( accountId );
04900   else {
04901     // Fallback: iterate over accounts to select folderId if found (as an inbox folder)
04902       for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0;
04903          a = kmkernel->acctMgr()->next() ) {
04904       if( a->folder() && a->folder()->child() ) {
04905         // Look inside that folder for an INBOX
04906         KMFolderNode *node;
04907         for (node = a->folder()->child()->first(); node; node = a->folder()->child()->next())
04908           if (!node->isDir() && node->name() == "INBOX") break;
04909 
04910         if ( node && static_cast<KMFolder*>(node)->idString() == folderId ) {
04911           selectedAccount = a;
04912           break;
04913         }
04914       }
04915     }
04916   }
04917   if ( selectedAccount )
04918     mAccountCombo->setCurrentAccount( selectedAccount );
04919   else if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == 1 )
04920     kdDebug(5006) << "Folder " << folderId << " not found as an account's inbox" << endl;
04921 }
04922 
04923 void MiscPage::GroupwareTab::save() {
04924   // Write the groupware config
04925   if ( mEnableGwCB )
04926     GlobalSettings::self()->setGroupwareEnabled( mEnableGwCB->isChecked() );
04927   GlobalSettings::self()->setLegacyMangleFromToHeaders( mLegacyMangleFromTo->isChecked() );
04928   GlobalSettings::self()->setLegacyBodyInvites( mLegacyBodyInvites->isChecked() );
04929   GlobalSettings::self()->setAutomaticSending( mAutomaticSending->isChecked() );
04930 
04931   int format = mStorageFormatCombo->currentItem();
04932   GlobalSettings::self()->setTheIMAPResourceStorageFormat( format );
04933 
04934   // Write the IMAP resource config
04935   GlobalSettings::self()->setHideGroupwareFolders( mHideGroupwareFolders->isChecked() );
04936   GlobalSettings::self()->setShowOnlyGroupwareFoldersForGroupwareAccount( mOnlyShowGroupwareFolders->isChecked() );
04937 
04938   // If there is a leftover folder in the foldercombo, getFolder can
04939   // return 0. In that case we really don't have it enabled
04940   QString folderId;
04941   if (  format == 0 ) {
04942     KMFolder* folder = mFolderCombo->folder();
04943     if (  folder )
04944       folderId = folder->idString();
04945   } else {
04946     // Inbox folder of the selected account
04947     KMAccount* acct = mAccountCombo->currentAccount();
04948     if (  acct ) {
04949       folderId = QString( ".%1.directory/INBOX" ).arg( acct->id() );
04950       GlobalSettings::self()->setTheIMAPResourceAccount( acct->id() );
04951     }
04952   }
04953 
04954   bool enabled = mEnableImapResCB->isChecked() && !folderId.isEmpty();
04955   GlobalSettings::self()->setTheIMAPResourceEnabled( enabled );
04956   GlobalSettings::self()->setTheIMAPResourceFolderLanguage( mLanguageCombo->currentItem() );
04957   GlobalSettings::self()->setTheIMAPResourceFolderParent( folderId );
04958 }
04959 
04960 void MiscPage::GroupwareTab::slotStorageFormatChanged( int format )
04961 {
04962   mLanguageCombo->setEnabled( format == 0 ); // only ical/vcard needs the language hack
04963   mFolderComboStack->raiseWidget( format );
04964   if ( format == 0 ) {
04965     mFolderComboLabel->setText( i18n("&Resource folders are subfolders of:") );
04966     mFolderComboLabel->setBuddy( mFolderCombo );
04967   } else {
04968     mFolderComboLabel->setText( i18n("&Resource folders are in account:") );
04969     mFolderComboLabel->setBuddy( mAccountCombo );
04970   }
04971   slotEmitChanged();
04972 }
04973 
04974 
04975 // *************************************************************
04976 // *                                                           *
04977 // *                     AccountUpdater                        *
04978 // *                                                           *
04979 // *************************************************************
04980 AccountUpdater::AccountUpdater(ImapAccountBase *account)
04981     : QObject()
04982 {
04983   mAccount = account;
04984 }
04985 
04986 void AccountUpdater::update()
04987 {
04988   connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
04989           this, SLOT( namespacesFetched() ) );
04990   mAccount->makeConnection();
04991 }
04992 
04993 void AccountUpdater::namespacesFetched()
04994 {
04995   mAccount->setCheckingMail( true );
04996   mAccount->processNewMail( false );
04997   deleteLater();
04998 }
04999 
05000 #undef DIM
05001 
05002 //----------------------------
05003 #include "configuredialog.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys