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