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