kmail Library API Documentation

configuredialog.cpp

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