kmail

configuredialog.cpp

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