kmail

kmmainwidget.cpp

00001 // -*- mode: C++; c-file-style: "gnu" -*-
00002 // kmmainwidget.cpp
00003 //#define MALLOC_DEBUG 1
00004 
00005 #ifdef HAVE_CONFIG_H
00006 #include <config.h>
00007 #endif
00008 
00009 #include <kwin.h>
00010 
00011 #ifdef MALLOC_DEBUG
00012 #include <malloc.h>
00013 #endif
00014 
00015 #undef Unsorted // X headers...
00016 #include <qaccel.h>
00017 #include <qlayout.h>
00018 #include <qhbox.h>
00019 #include <qvbox.h>
00020 #include <qpopupmenu.h>
00021 
00022 #include <kopenwith.h>
00023 
00024 #include <kmessagebox.h>
00025 
00026 #include <kpopupmenu.h>
00027 #include <kaccelmanager.h>
00028 #include <kglobalsettings.h>
00029 #include <kstdaccel.h>
00030 #include <kkeydialog.h>
00031 #include <kcharsets.h>
00032 #include <knotifyclient.h>
00033 #include <kdebug.h>
00034 #include <kapplication.h>
00035 #include <kfiledialog.h>
00036 #include <ktip.h>
00037 #include <knotifydialog.h>
00038 #include <kstandarddirs.h>
00039 #include <dcopclient.h>
00040 #include <kaddrbook.h>
00041 #include <kaccel.h>
00042 #include <kstringhandler.h>
00043 
00044 #include <qvaluevector.h>
00045 
00046 #include "globalsettings.h"
00047 #include "kcursorsaver.h"
00048 #include "broadcaststatus.h"
00049 using KPIM::BroadcastStatus;
00050 #include "kmfoldermgr.h"
00051 #include "kmfolderdia.h"
00052 #include "accountmanager.h"
00053 using KMail::AccountManager;
00054 #include "kmfilter.h"
00055 #include "kmfoldertree.h"
00056 #include "kmreadermainwin.h"
00057 #include "kmfoldercachedimap.h"
00058 #include "kmfolderimap.h"
00059 #include "kmacctcachedimap.h"
00060 #include "composer.h"
00061 #include "kmfolderseldlg.h"
00062 #include "kmfiltermgr.h"
00063 #include "messagesender.h"
00064 #include "kmaddrbook.h"
00065 #include "kmversion.h"
00066 #include "searchwindow.h"
00067 using KMail::SearchWindow;
00068 #include "kmacctfolder.h"
00069 #include "undostack.h"
00070 #include "kmcommands.h"
00071 #include "kmmainwin.h"
00072 #include "kmsystemtray.h"
00073 #include "imapaccountbase.h"
00074 #include "transportmanager.h"
00075 using KMail::ImapAccountBase;
00076 #include "vacation.h"
00077 using KMail::Vacation;
00078 
00079 #include <qsignalmapper.h>
00080 
00081 #include "subscriptiondialog.h"
00082 using KMail::SubscriptionDialog;
00083 #include "localsubscriptiondialog.h"
00084 using KMail::LocalSubscriptionDialog;
00085 #include "attachmentstrategy.h"
00086 using KMail::AttachmentStrategy;
00087 #include "headerstrategy.h"
00088 using KMail::HeaderStrategy;
00089 #include "headerstyle.h"
00090 using KMail::HeaderStyle;
00091 #include "folderjob.h"
00092 using KMail::FolderJob;
00093 #include "mailinglist-magic.h"
00094 #include "antispamwizard.h"
00095 using KMail::AntiSpamWizard;
00096 #include "filterlogdlg.h"
00097 using KMail::FilterLogDialog;
00098 #include <headerlistquicksearch.h>
00099 #include "klistviewindexedsearchline.h"
00100 using KMail::HeaderListQuickSearch;
00101 #include "kmheaders.h"
00102 #include "mailinglistpropertiesdialog.h"
00103 #include "templateparser.h"
00104 
00105 #if !defined(NDEBUG)
00106     #include "sievedebugdialog.h"
00107     using KMail::SieveDebugDialog;
00108 #endif
00109 
00110 #include <libkpimidentities/identity.h>
00111 #include <libkpimidentities/identitymanager.h>
00112 
00113 #include <assert.h>
00114 #include <kstatusbar.h>
00115 #include <kstaticdeleter.h>
00116 #include <kaction.h>
00117 
00118 #include <kmime_mdn.h>
00119 #include <kmime_header_parsing.h>
00120 using namespace KMime;
00121 using KMime::Types::AddrSpecList;
00122 
00123 #include "progressmanager.h"
00124 using KPIM::ProgressManager;
00125 
00126 #include "managesievescriptsdialog.h"
00127 #include <qstylesheet.h>
00128 
00129 #include "customtemplates.h"
00130 #include "customtemplates_kfg.h"
00131 
00132 #include "kmmainwidget.moc"
00133 
00134 QValueList<KMMainWidget*>* KMMainWidget::s_mainWidgetList = 0;
00135 static KStaticDeleter<QValueList<KMMainWidget*> > mwlsd;
00136 
00137 //-----------------------------------------------------------------------------
00138 KMMainWidget::KMMainWidget(QWidget *parent, const char *name,
00139                            KXMLGUIClient *aGUIClient,
00140                            KActionCollection *actionCollection, KConfig* config ) :
00141     QWidget(parent, name),
00142     mQuickSearchLine( 0 ),
00143     mShowBusySplashTimer( 0 ),
00144     mShowingOfflineScreen( false )
00145 {
00146   // must be the first line of the constructor:
00147   mStartupDone = FALSE;
00148   mSearchWin = 0;
00149   mIntegrated  = TRUE;
00150   mFolder = 0;
00151   mTemplateFolder = 0;
00152   mFolderThreadPref = false;
00153   mFolderThreadSubjPref = true;
00154   mReaderWindowActive = true;
00155   mReaderWindowBelow = true;
00156   mFolderHtmlPref = false;
00157   mFolderHtmlLoadExtPref = false;
00158   mSystemTray = 0;
00159   mDestructed = false;
00160   mActionCollection = actionCollection;
00161   mTopLayout = new QVBoxLayout(this);
00162   mFilterMenuActions.setAutoDelete(true);
00163   mFilterTBarActions.setAutoDelete(false);
00164   mFilterCommands.setAutoDelete(true);
00165   mFolderShortcutCommands.setAutoDelete(true);
00166   mJob = 0;
00167   mConfig = config;
00168   mGUIClient = aGUIClient;
00169   mOpenedImapFolder = false;
00170 
00171   mCustomReplyActionMenu = 0;
00172   mCustomReplyAllActionMenu = 0;
00173   mCustomForwardActionMenu = 0;
00174   mCustomReplyMapper = 0;
00175   mCustomReplyAllMapper = 0;
00176   mCustomForwardMapper = 0;
00177 
00178   // FIXME This should become a line separator as soon as the API
00179   // is extended in kdelibs.
00180   mToolbarActionSeparator = new KActionSeparator( actionCollection );
00181 
00182   if( !s_mainWidgetList )
00183     mwlsd.setObject( s_mainWidgetList, new QValueList<KMMainWidget*>() );
00184   s_mainWidgetList->append( this );
00185 
00186   mPanner1Sep << 1 << 1;
00187   mPanner2Sep << 1 << 1;
00188 
00189   setMinimumSize(400, 300);
00190 
00191   readPreConfig();
00192   createWidgets();
00193 
00194   setupActions();
00195 
00196   readConfig();
00197 
00198   activatePanners();
00199 
00200   QTimer::singleShot( 0, this, SLOT( slotShowStartupFolder() ));
00201 
00202   connect( kmkernel->acctMgr(), SIGNAL( checkedMail( bool, bool, const QMap<QString, int> & ) ),
00203            this, SLOT( slotMailChecked( bool, bool, const QMap<QString, int> & ) ) );
00204 
00205   connect( kmkernel->acctMgr(), SIGNAL( accountAdded( KMAccount* ) ),
00206            this, SLOT( initializeIMAPActions() ) );
00207   connect( kmkernel->acctMgr(), SIGNAL( accountRemoved( KMAccount* ) ),
00208            this, SLOT( initializeIMAPActions() ) );
00209 
00210   connect(kmkernel, SIGNAL( configChanged() ),
00211           this, SLOT( slotConfigChanged() ));
00212 
00213   // display the full path to the folder in the caption
00214   connect(mFolderTree, SIGNAL(currentChanged(QListViewItem*)),
00215       this, SLOT(slotChangeCaption(QListViewItem*)));
00216   connect(mFolderTree, SIGNAL(selectionChanged()),
00217           SLOT(updateFolderMenu()) );
00218 
00219   connect(kmkernel->folderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00220           this, SLOT(slotFolderRemoved(KMFolder*)));
00221 
00222   connect(kmkernel->imapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00223           this, SLOT(slotFolderRemoved(KMFolder*)));
00224 
00225   connect(kmkernel->dimapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00226           this, SLOT(slotFolderRemoved(KMFolder*)));
00227 
00228   connect(kmkernel->searchFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00229           this, SLOT(slotFolderRemoved(KMFolder*)));
00230 
00231   connect( kmkernel, SIGNAL( onlineStatusChanged( GlobalSettings::EnumNetworkState::type ) ),
00232            this, SLOT( slotUpdateOnlineStatus( GlobalSettings::EnumNetworkState::type ) ) );
00233 
00234   toggleSystemTray();
00235 
00236   // must be the last line of the constructor:
00237   mStartupDone = TRUE;
00238 }
00239 
00240 
00241 //-----------------------------------------------------------------------------
00242 //The kernel may have already been deleted when this method is called,
00243 //perform all cleanup that requires the kernel in destruct()
00244 KMMainWidget::~KMMainWidget()
00245 {
00246   s_mainWidgetList->remove( this );
00247   destruct();
00248 }
00249 
00250 
00251 //-----------------------------------------------------------------------------
00252 //This method performs all cleanup that requires the kernel to exist.
00253 void KMMainWidget::destruct()
00254 {
00255   if (mDestructed)
00256     return;
00257   if (mSearchWin)
00258     mSearchWin->close();
00259   writeConfig();
00260   writeFolderConfig();
00261   delete mHeaders;
00262   delete mFolderTree;
00263   delete mSystemTray;
00264   delete mMsgView;
00265   mDestructed = true;
00266 }
00267 
00268 
00269 //-----------------------------------------------------------------------------
00270 void KMMainWidget::readPreConfig(void)
00271 {
00272   const KConfigGroup geometry( KMKernel::config(), "Geometry" );
00273   const KConfigGroup reader( KMKernel::config(), "Reader" );
00274 
00275   mLongFolderList = geometry.readEntry( "FolderList", "long" ) != "short";
00276   mReaderWindowActive = geometry.readEntry( "readerWindowMode", "below" ) != "hide";
00277   mReaderWindowBelow = geometry.readEntry( "readerWindowMode", "below" ) == "below";
00278   mThreadPref = geometry.readBoolEntry( "nestedMessages", false );
00279 
00280   mHtmlPref = reader.readBoolEntry( "htmlMail", false );
00281   mHtmlLoadExtPref = reader.readBoolEntry( "htmlLoadExternal", false );
00282 }
00283 
00284 
00285 //-----------------------------------------------------------------------------
00286 void KMMainWidget::readFolderConfig(void)
00287 {
00288   if (!mFolder)
00289     return;
00290 
00291   KConfig *config = KMKernel::config();
00292   KConfigGroupSaver saver(config, "Folder-" + mFolder->idString());
00293   mFolderThreadPref = config->readBoolEntry( "threadMessagesOverride", false );
00294   mFolderThreadSubjPref = config->readBoolEntry( "threadMessagesBySubject", true );
00295   mFolderHtmlPref = config->readBoolEntry( "htmlMailOverride", false );
00296   mFolderHtmlLoadExtPref = config->readBoolEntry( "htmlLoadExternalOverride", false );
00297 }
00298 
00299 
00300 //-----------------------------------------------------------------------------
00301 void KMMainWidget::writeFolderConfig(void)
00302 {
00303   if (!mFolder)
00304     return;
00305 
00306   KConfig *config = KMKernel::config();
00307   KConfigGroupSaver saver(config, "Folder-" + mFolder->idString());
00308   config->writeEntry( "threadMessagesOverride", mFolderThreadPref );
00309   config->writeEntry( "threadMessagesBySubject", mFolderThreadSubjPref );
00310   config->writeEntry( "htmlMailOverride", mFolderHtmlPref );
00311   config->writeEntry( "htmlLoadExternalOverride", mFolderHtmlLoadExtPref );
00312 }
00313 
00314 
00315 //-----------------------------------------------------------------------------
00316 void KMMainWidget::readConfig(void)
00317 {
00318   KConfig *config = KMKernel::config();
00319 
00320   bool oldLongFolderList =  mLongFolderList;
00321   bool oldReaderWindowActive = mReaderWindowActive;
00322   bool oldReaderWindowBelow = mReaderWindowBelow;
00323 
00324   QString str;
00325   QSize siz;
00326 
00327   if (mStartupDone)
00328   {
00329     writeConfig();
00330 
00331     readPreConfig();
00332     mHeaders->refreshNestedState();
00333 
00334     bool layoutChanged = ( oldLongFolderList != mLongFolderList )
00335                     || ( oldReaderWindowActive != mReaderWindowActive )
00336                     || ( oldReaderWindowBelow != mReaderWindowBelow );
00337 
00338 
00339     if( layoutChanged ) {
00340       hide();
00341       // delete all panners
00342       delete mPanner1; // will always delete the others
00343       createWidgets();
00344     }
00345 
00346   }
00347 
00348   { // area for config group "Geometry"
00349     KConfigGroupSaver saver(config, "Geometry");
00350     // size of the mainwin
00351     QSize defaultSize(750,560);
00352     siz = config->readSizeEntry("MainWin", &defaultSize);
00353     if (!siz.isEmpty())
00354       resize(siz);
00355     // default width of the foldertree
00356     static const int folderpanewidth = 250;
00357 
00358     const int folderW = config->readNumEntry( "FolderPaneWidth", folderpanewidth );
00359     const int headerW = config->readNumEntry( "HeaderPaneWidth", width()-folderpanewidth );
00360     const int headerH = config->readNumEntry( "HeaderPaneHeight", 180 );
00361     const int readerH = config->readNumEntry( "ReaderPaneHeight", 280 );
00362 
00363     mPanner1Sep.clear();
00364     mPanner2Sep.clear();
00365     QValueList<int> & widths = mLongFolderList ? mPanner1Sep : mPanner2Sep ;
00366     QValueList<int> & heights = mLongFolderList ? mPanner2Sep : mPanner1Sep ;
00367 
00368     widths << folderW << headerW;
00369     heights << headerH << readerH;
00370 
00371     bool layoutChanged = ( oldLongFolderList != mLongFolderList )
00372                     || ( oldReaderWindowActive != mReaderWindowActive )
00373                     || ( oldReaderWindowBelow != mReaderWindowBelow );
00374 
00375     if (!mStartupDone || layoutChanged )
00376     {
00380       // The columns are shown by default.
00381 
00382       const int unreadColumn = config->readNumEntry("UnreadColumn", 1);
00383       const int totalColumn = config->readNumEntry("TotalColumn", 2);
00384 
00385       /* we need to _activate_ them in the correct order
00386       * this is ugly because we can't use header()->moveSection
00387       * but otherwise the restoreLayout from KMFolderTree
00388       * doesn't know that to do */
00389       if (unreadColumn != -1 && unreadColumn < totalColumn)
00390         mFolderTree->addUnreadColumn( i18n("Unread"), 70 );
00391       if (totalColumn != -1)
00392         mFolderTree->addTotalColumn( i18n("Total"), 70 );
00393       if (unreadColumn != -1 && unreadColumn > totalColumn)
00394         mFolderTree->addUnreadColumn( i18n("Unread"), 70 );
00395       mUnreadColumnToggle->setChecked( mFolderTree->isUnreadActive() );
00396       mUnreadTextToggle->setChecked( !mFolderTree->isUnreadActive() );
00397       mTotalColumnToggle->setChecked( mFolderTree->isTotalActive() );
00398 
00399       mFolderTree->updatePopup();
00400     }
00401   }
00402 
00403   if (mMsgView)
00404     mMsgView->readConfig();
00405 
00406   mHeaders->readConfig();
00407   mHeaders->restoreLayout(KMKernel::config(), "Header-Geometry");
00408 
00409   mFolderTree->readConfig();
00410 
00411   { // area for config group "General"
00412     KConfigGroupSaver saver(config, "General");
00413     mBeepOnNew = config->readBoolEntry("beep-on-mail", false);
00414     mConfirmEmpty = config->readBoolEntry("confirm-before-empty", true);
00415     // startup-Folder, defaults to system-inbox
00416     mStartupFolder = config->readEntry("startupFolder", kmkernel->inboxFolder()->idString());
00417     if (!mStartupDone)
00418     {
00419       // check mail on startup
00420       bool check = config->readBoolEntry("checkmail-startup", false);
00421       if (check)
00422         // do it after building the kmmainwin, so that the progressdialog is available
00423         QTimer::singleShot( 0, this, SLOT( slotCheckMail() ) );
00424     }
00425   }
00426 
00427   // reload foldertree
00428   mFolderTree->reload();
00429 
00430   // Re-activate panners
00431   if (mStartupDone)
00432   {
00433     // Update systray
00434     toggleSystemTray();
00435 
00436     bool layoutChanged = ( oldLongFolderList != mLongFolderList )
00437                     || ( oldReaderWindowActive != mReaderWindowActive )
00438                     || ( oldReaderWindowBelow != mReaderWindowBelow );
00439     if ( layoutChanged ) {
00440       activatePanners();
00441     }
00442 
00443     mFolderTree->showFolder( mFolder );
00444 
00445     // sanders - New code
00446     mHeaders->setFolder(mFolder);
00447     if (mMsgView) {
00448       int aIdx = mHeaders->currentItemIndex();
00449       if (aIdx != -1)
00450         mMsgView->setMsg( mFolder->getMsg(aIdx), true );
00451       else
00452         mMsgView->clear( true );
00453     }
00454     updateMessageActions();
00455     show();
00456     // sanders - Maybe this fixes a bug?
00457 
00458   }
00459   updateMessageMenu();
00460   updateFileMenu();
00461 }
00462 
00463 
00464 //-----------------------------------------------------------------------------
00465 void KMMainWidget::writeConfig(void)
00466 {
00467   QString s;
00468   KConfig *config = KMKernel::config();
00469   KConfigGroup geometry( config, "Geometry" );
00470 
00471   if (mMsgView)
00472     mMsgView->writeConfig();
00473 
00474   mFolderTree->writeConfig();
00475 
00476   geometry.writeEntry( "MainWin", this->geometry().size() );
00477 
00478   const QValueList<int> widths = ( mLongFolderList ? mPanner1 : mPanner2 )->sizes();
00479   const QValueList<int> heights = ( mLongFolderList ? mPanner2 : mPanner1 )->sizes();
00480 
00481   geometry.writeEntry( "FolderPaneWidth", widths[0] );
00482   geometry.writeEntry( "HeaderPaneWidth", widths[1] );
00483 
00484   // Only save when the widget is shown (to avoid saving a wrong value)
00485   if ( mSearchAndHeaders && mSearchAndHeaders->isShown() ) {
00486     geometry.writeEntry( "HeaderPaneHeight", heights[0] );
00487     geometry.writeEntry( "ReaderPaneHeight", heights[1] );
00488   }
00489 
00490   // save the state of the unread/total-columns
00491   geometry.writeEntry( "UnreadColumn", mFolderTree->unreadIndex() );
00492   geometry.writeEntry( "TotalColumn", mFolderTree->totalIndex() );
00493 }
00494 
00495 
00496 //-----------------------------------------------------------------------------
00497 void KMMainWidget::createWidgets(void)
00498 {
00499   // Create the splitters according to the layout settings
00500   QWidget *headerParent = 0, *folderParent = 0,
00501             *mimeParent = 0, *messageParent = 0;
00502 
00503   const bool opaqueResize = KGlobalSettings::opaqueResize();
00504   if ( mLongFolderList ) {
00505     // superior splitter: folder tree vs. rest
00506     // inferior splitter: headers vs. message vs. mime tree
00507     mPanner1 = new QSplitter( Qt::Horizontal, this, "panner 1" );
00508     mPanner1->setOpaqueResize( opaqueResize );
00509     Qt::Orientation orientation = mReaderWindowBelow ? Qt::Vertical : Qt::Horizontal;
00510     mPanner2 = new QSplitter( orientation, mPanner1, "panner 2" );
00511     mPanner2->setOpaqueResize( opaqueResize );
00512     folderParent = mPanner1;
00513     headerParent = mimeParent = messageParent = mPanner2;
00514   } else /* !mLongFolderList */ {
00515     // superior splitter: ( folder tree + headers ) vs. message vs. mime
00516     // inferior splitter: folder tree vs. headers
00517     mPanner1 = new QSplitter( Qt::Vertical, this, "panner 1" );
00518     mPanner1->setOpaqueResize( opaqueResize );
00519     mPanner2 = new QSplitter( Qt::Horizontal, mPanner1, "panner 2" );
00520     mPanner2->setOpaqueResize( opaqueResize );
00521     headerParent = folderParent = mPanner2;
00522     mimeParent = messageParent = mPanner1;
00523   }
00524 
00525 #ifndef NDEBUG
00526   if( mPanner1 ) mPanner1->dumpObjectTree();
00527   if( mPanner2 ) mPanner2->dumpObjectTree();
00528 #endif
00529 
00530   mTopLayout->add( mPanner1 );
00531 
00532   // BUG -sanders these accelerators stop working after switching
00533   // between long/short folder layout
00534   // Probably need to disconnect them first.
00535 
00536   // create list of messages
00537 #ifndef NDEBUG
00538   headerParent->dumpObjectTree();
00539 #endif
00540   mSearchAndHeaders = new QVBox( headerParent );
00541   mSearchToolBar = new KToolBar( mSearchAndHeaders, "search toolbar");
00542   mSearchToolBar->setMovingEnabled(false);
00543   mSearchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() );
00544   QLabel *label = new QLabel( i18n("S&earch:"), mSearchToolBar, "kde toolbar widget" );
00545 
00546 
00547   mHeaders = new KMHeaders(this, mSearchAndHeaders, "headers");
00548 #ifdef HAVE_INDEXLIB
00549   mQuickSearchLine = new KListViewIndexedSearchLine( mSearchToolBar, mHeaders,
00550                                                     actionCollection(), "headers quick search line" );
00551 #else
00552   mQuickSearchLine = new HeaderListQuickSearch( mSearchToolBar, mHeaders,
00553                         actionCollection(), "headers quick search line" );
00554 #endif
00555   label->setBuddy( mQuickSearchLine );
00556   mSearchToolBar->setStretchableWidget( mQuickSearchLine );
00557     connect( mHeaders, SIGNAL( messageListUpdated() ),
00558            mQuickSearchLine, SLOT( updateSearch() ) );
00559   if ( !GlobalSettings::self()->quickSearchActive() ) mSearchToolBar->hide();
00560 
00561   if (mReaderWindowActive) {
00562     connect(mHeaders, SIGNAL(selected(KMMessage*)),
00563             this, SLOT(slotMsgSelected(KMMessage*)));
00564   }
00565   connect(mHeaders, SIGNAL(activated(KMMessage*)),
00566           this, SLOT(slotMsgActivated(KMMessage*)));
00567   connect( mHeaders, SIGNAL( selectionChanged() ),
00568            SLOT( startUpdateMessageActionsTimer() ) );
00569   QAccel *accel = actionCollection()->kaccel();
00570   accel->connectItem(accel->insertItem(SHIFT+Key_Left),
00571                      mHeaders, SLOT(selectPrevMessage()));
00572   accel->connectItem(accel->insertItem(SHIFT+Key_Right),
00573                      mHeaders, SLOT(selectNextMessage()));
00574 
00575   if (mReaderWindowActive) {
00576     mMsgView = new KMReaderWin(messageParent, this, actionCollection(), 0 );
00577 
00578     connect(mMsgView, SIGNAL(replaceMsgByUnencryptedVersion()),
00579         this, SLOT(slotReplaceMsgByUnencryptedVersion()));
00580     connect(mMsgView, SIGNAL(popupMenu(KMMessage&,const KURL&,const QPoint&)),
00581         this, SLOT(slotMsgPopup(KMMessage&,const KURL&,const QPoint&)));
00582     connect(mMsgView, SIGNAL(urlClicked(const KURL&,int)),
00583         mMsgView, SLOT(slotUrlClicked()));
00584     connect(mHeaders, SIGNAL(maybeDeleting()),
00585         mMsgView, SLOT(clearCache()));
00586     connect(mMsgView, SIGNAL(noDrag()),
00587         mHeaders, SLOT(slotNoDrag()));
00588     accel->connectItem(accel->insertItem(Key_Up),
00589         mMsgView, SLOT(slotScrollUp()));
00590     accel->connectItem(accel->insertItem(Key_Down),
00591         mMsgView, SLOT(slotScrollDown()));
00592     accel->connectItem(accel->insertItem(Key_Prior),
00593         mMsgView, SLOT(slotScrollPrior()));
00594     accel->connectItem(accel->insertItem(Key_Next),
00595         mMsgView, SLOT(slotScrollNext()));
00596   } else {
00597     mMsgView = NULL;
00598   }
00599 
00600   KAction *action;
00601 
00602   action = new KAction( i18n("Move Message to Folder"), Key_M, this,
00603                SLOT(slotMoveMsg()), actionCollection(),
00604                "move_message_to_folder" );
00605   action->plugAccel( actionCollection()->kaccel() );
00606 
00607   action = new KAction( i18n("Copy Message to Folder"), Key_C, this,
00608                SLOT(slotCopyMsg()), actionCollection(),
00609                "copy_message_to_folder" );
00610   action->plugAccel( actionCollection()->kaccel() );
00611 
00612   action = new KAction( i18n("Jump to Folder"), Key_J, this,
00613                SLOT(slotJumpToFolder()), actionCollection(),
00614                "jump_to_folder" );
00615   action->plugAccel( actionCollection()->kaccel() );
00616 
00617   // create list of folders
00618   mFolderTree = new KMFolderTree(this, folderParent, "folderTree");
00619 
00620   connect(mFolderTree, SIGNAL(folderSelected(KMFolder*)),
00621       this, SLOT(folderSelected(KMFolder*)));
00622   connect( mFolderTree, SIGNAL( folderSelected( KMFolder* ) ),
00623            mQuickSearchLine, SLOT( reset() ) );
00624   connect(mFolderTree, SIGNAL(folderSelectedUnread(KMFolder*)),
00625       this, SLOT(folderSelectedUnread(KMFolder*)));
00626   connect(mFolderTree, SIGNAL(folderDrop(KMFolder*)),
00627       this, SLOT(slotMoveMsgToFolder(KMFolder*)));
00628   connect(mFolderTree, SIGNAL(folderDropCopy(KMFolder*)),
00629           this, SLOT(slotCopyMsgToFolder(KMFolder*)));
00630   connect(mFolderTree, SIGNAL(columnsChanged()),
00631           this, SLOT(slotFolderTreeColumnsChanged()));
00632 
00633   //Commands not worthy of menu items, but that deserve configurable keybindings
00634   mRemoveDuplicatesAction = new KAction(
00635     i18n("Remove Duplicate Messages"), CTRL+Key_Asterisk, this,
00636     SLOT(removeDuplicates()), actionCollection(), "remove_duplicate_messages");
00637   action->plugAccel( actionCollection()->kaccel() );
00638 
00639   action = new KAction(
00640     i18n("Abort Current Operation"), Key_Escape, ProgressManager::instance(),
00641     SLOT(slotAbortAll()), actionCollection(), "cancel" );
00642   action->plugAccel( actionCollection()->kaccel() );
00643 
00644   action = new KAction(
00645    i18n("Focus on Next Folder"), CTRL+Key_Right, mFolderTree,
00646    SLOT(incCurrentFolder()), actionCollection(), "inc_current_folder");
00647   action->plugAccel( actionCollection()->kaccel() );
00648 
00649   action = new KAction(
00650    i18n("Focus on Previous Folder"), CTRL+Key_Left, mFolderTree,
00651    SLOT(decCurrentFolder()), actionCollection(), "dec_current_folder");
00652   action->plugAccel( actionCollection()->kaccel() );
00653 
00654   action = new KAction(
00655    i18n("Select Folder with Focus"), CTRL+Key_Space, mFolderTree,
00656    SLOT(selectCurrentFolder()), actionCollection(), "select_current_folder");
00657   action->plugAccel( actionCollection()->kaccel() );
00658 
00659   action = new KAction(
00660     i18n("Focus on Next Message"), ALT+Key_Right, mHeaders,
00661     SLOT(incCurrentMessage()), actionCollection(), "inc_current_message");
00662   action->plugAccel( actionCollection()->kaccel() );
00663 
00664   action = new KAction(
00665     i18n("Focus on Previous Message"), ALT+Key_Left, mHeaders,
00666     SLOT(decCurrentMessage()), actionCollection(), "dec_current_message");
00667   action->plugAccel( actionCollection()->kaccel() );
00668 
00669   action = new KAction(
00670     i18n("Select Message with Focus"), ALT+Key_Space, mHeaders,
00671     SLOT( selectCurrentMessage() ), actionCollection(), "select_current_message");
00672   action->plugAccel( actionCollection()->kaccel() );
00673 
00674   connect( kmkernel->outboxFolder(), SIGNAL( msgRemoved(int, QString) ),
00675            SLOT( startUpdateMessageActionsTimer() ) );
00676   connect( kmkernel->outboxFolder(), SIGNAL( msgAdded(int) ),
00677            SLOT( startUpdateMessageActionsTimer() ) );
00678 }
00679 
00680 
00681 //-----------------------------------------------------------------------------
00682 void KMMainWidget::activatePanners(void)
00683 {
00684   if (mMsgView) {
00685     QObject::disconnect( mMsgView->copyAction(),
00686         SIGNAL( activated() ),
00687         mMsgView, SLOT( slotCopySelectedText() ));
00688   }
00689   if ( mLongFolderList ) {
00690     mSearchAndHeaders->reparent( mPanner2, 0, QPoint( 0, 0 ) );
00691     if (mMsgView) {
00692       mMsgView->reparent( mPanner2, 0, QPoint( 0, 0 ) );
00693       mPanner2->moveToLast( mMsgView );
00694     }
00695     mFolderTree->reparent( mPanner1, 0, QPoint( 0, 0 ) );
00696     mPanner1->moveToLast( mPanner2 );
00697     mPanner1->setSizes( mPanner1Sep );
00698     mPanner1->setResizeMode( mFolderTree, QSplitter::KeepSize );
00699     mPanner2->setSizes( mPanner2Sep );
00700     mPanner2->setResizeMode( mSearchAndHeaders, QSplitter::KeepSize );
00701   } else /* !mLongFolderList */ {
00702     mFolderTree->reparent( mPanner2, 0, QPoint( 0, 0 ) );
00703     mSearchAndHeaders->reparent( mPanner2, 0, QPoint( 0, 0 ) );
00704     mPanner2->moveToLast( mSearchAndHeaders );
00705     mPanner1->moveToFirst( mPanner2 );
00706     if (mMsgView) {
00707       mMsgView->reparent( mPanner1, 0, QPoint( 0, 0 ) );
00708       mPanner1->moveToLast( mMsgView );
00709     }
00710     mPanner1->setSizes( mPanner1Sep );
00711     mPanner2->setSizes( mPanner2Sep );
00712     mPanner1->setResizeMode( mPanner2, QSplitter::KeepSize );
00713     mPanner2->setResizeMode( mFolderTree, QSplitter::KeepSize );
00714   }
00715 
00716   if (mMsgView) {
00717     QObject::connect( mMsgView->copyAction(),
00718             SIGNAL( activated() ),
00719             mMsgView, SLOT( slotCopySelectedText() ));
00720   }
00721 }
00722 
00723 
00724 //-----------------------------------------------------------------------------
00725 void KMMainWidget::hide()
00726 {
00727   QWidget::hide();
00728 }
00729 
00730 
00731 //-----------------------------------------------------------------------------
00732 void KMMainWidget::show()
00733 {
00734   QWidget::show();
00735 }
00736 
00737 //-------------------------------------------------------------------------
00738 void KMMainWidget::slotSearch()
00739 {
00740   if(!mSearchWin)
00741   {
00742     mSearchWin = new SearchWindow(this, "Search", mFolder, false);
00743     connect(mSearchWin, SIGNAL(destroyed()),
00744         this, SLOT(slotSearchClosed()));
00745   }
00746   else
00747   {
00748     mSearchWin->activateFolder(mFolder);
00749   }
00750 
00751   mSearchWin->show();
00752   KWin::activateWindow( mSearchWin->winId() );
00753 }
00754 
00755 
00756 //-------------------------------------------------------------------------
00757 void KMMainWidget::slotSearchClosed()
00758 {
00759   mSearchWin = 0;
00760 }
00761 
00762 
00763 //-------------------------------------------------------------------------
00764 void KMMainWidget::slotFind()
00765 {
00766   if( mMsgView )
00767     mMsgView->slotFind();
00768 }
00769 
00770 
00771 //-----------------------------------------------------------------------------
00772 void KMMainWidget::slotHelp()
00773 {
00774   kapp->invokeHelp();
00775 }
00776 
00777 
00778 //-----------------------------------------------------------------------------
00779 void KMMainWidget::slotFilter()
00780 {
00781   kmkernel->filterMgr()->openDialog( this );
00782 }
00783 
00784 
00785 //-----------------------------------------------------------------------------
00786 void KMMainWidget::slotPopFilter()
00787 {
00788   kmkernel->popFilterMgr()->openDialog( this );
00789 }
00790 
00791 void KMMainWidget::slotManageSieveScripts()
00792 {
00793   if ( !kmkernel->askToGoOnline() ) {
00794     return;
00795   }
00796   KMail::ManageSieveScriptsDialog * dlg = new KMail::ManageSieveScriptsDialog( this );
00797   dlg->show();
00798 }
00799 
00800 
00801 //-----------------------------------------------------------------------------
00802 void KMMainWidget::slotAddrBook()
00803 {
00804   KAddrBookExternal::openAddressBook(this);
00805 }
00806 
00807 
00808 //-----------------------------------------------------------------------------
00809 void KMMainWidget::slotImport()
00810 {
00811   KRun::runCommand("kmailcvt");
00812 }
00813 
00814 //-----------------------------------------------------------------------------
00815 void KMMainWidget::slotCheckMail()
00816 {
00817   if ( !kmkernel->askToGoOnline() ) {
00818     return;
00819   }
00820   kmkernel->acctMgr()->checkMail(true);
00821 }
00822 
00823 //-----------------------------------------------------------------------------
00824 void KMMainWidget::slotCheckOneAccount(int item)
00825 {
00826   if ( !kmkernel->askToGoOnline() ) {
00827     return;
00828   }
00829   kmkernel->acctMgr()->intCheckMail(item);
00830 }
00831 
00832 //-----------------------------------------------------------------------------
00833 void KMMainWidget::slotMailChecked( bool newMail, bool sendOnCheck,
00834                                     const QMap<QString, int> & newInFolder )
00835 {
00836   const bool sendOnAll =
00837     GlobalSettings::self()->sendOnCheck() == GlobalSettings::EnumSendOnCheck::SendOnAllChecks;
00838   const bool sendOnManual =
00839     GlobalSettings::self()->sendOnCheck() == GlobalSettings::EnumSendOnCheck::SendOnManualChecks;
00840   if( sendOnAll || (sendOnManual && sendOnCheck ) )
00841     slotSendQueued();
00842 
00843   if ( !newMail || newInFolder.isEmpty() )
00844     return;
00845 
00846   kapp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", QByteArray() );
00847 
00848   // build summary for new mail message
00849   bool showNotification = false;
00850   QString summary;
00851   QStringList keys( newInFolder.keys() );
00852   keys.sort();
00853   for ( QStringList::const_iterator it = keys.begin();
00854         it != keys.end();
00855         ++it ) {
00856     kdDebug(5006) << newInFolder.find( *it ).data() << " new message(s) in "
00857                   << *it << endl;
00858 
00859     KMFolder *folder = kmkernel->findFolderById( *it );
00860 
00861     if ( folder && !folder->ignoreNewMail() ) {
00862       showNotification = true;
00863       if ( GlobalSettings::self()->verboseNewMailNotification() ) {
00864         summary += "<br>" + i18n( "1 new message in %1",
00865                                   "%n new messages in %1",
00866                                   newInFolder.find( *it ).data() )
00867                             .arg( folder->prettyURL() );
00868       }
00869     }
00870   }
00871 
00872   // update folder menus in case some mail got filtered to trash/current folder
00873   // and we can enable "empty trash/move all to trash" action etc.
00874   updateFolderMenu();
00875 
00876   if ( !showNotification )
00877     return;
00878 
00879   if ( GlobalSettings::self()->verboseNewMailNotification() ) {
00880     summary = i18n( "%1 is a list of the number of new messages per folder",
00881                     "<b>New mail arrived</b><br>%1" )
00882               .arg( summary );
00883   }
00884   else {
00885     summary = i18n( "New mail arrived" );
00886   }
00887 
00888   if(kmkernel->xmlGuiInstance()) {
00889     KNotifyClient::Instance instance(kmkernel->xmlGuiInstance());
00890     KNotifyClient::event( topLevelWidget()->winId(), "new-mail-arrived",
00891                           summary );
00892   }
00893   else
00894     KNotifyClient::event( topLevelWidget()->winId(), "new-mail-arrived",
00895                           summary );
00896 
00897   if (mBeepOnNew) {
00898     KNotifyClient::beep();
00899   }
00900 }
00901 
00902 
00903 //-----------------------------------------------------------------------------
00904 void KMMainWidget::slotCompose()
00905 {
00906   KMail::Composer * win;
00907   KMMessage* msg = new KMMessage;
00908 
00909   if ( mFolder ) {
00910       msg->initHeader( mFolder->identity() );
00911       TemplateParser parser( msg, TemplateParser::NewMessage,
00912     "", false, false, false, false );
00913       parser.process( NULL, mFolder );
00914       win = KMail::makeComposer( msg, mFolder->identity() );
00915   } else {
00916       msg->initHeader();
00917       TemplateParser parser( msg, TemplateParser::NewMessage,
00918     "", false, false, false, false );
00919       parser.process( NULL, NULL );
00920       win = KMail::makeComposer( msg );
00921   }
00922 
00923   win->show();
00924 
00925 }
00926 
00927 //-----------------------------------------------------------------------------
00928 // TODO: do we want the list sorted alphabetically?
00929 void KMMainWidget::slotShowNewFromTemplate()
00930 {
00931   if ( mFolder ) {
00932     const KPIM::Identity & ident =
00933       kmkernel->identityManager()->identityForUoidOrDefault( mFolder->identity() );
00934     mTemplateFolder = kmkernel->folderMgr()->findIdString( ident.templates() );
00935   }
00936   else mTemplateFolder = kmkernel->templatesFolder();
00937   if ( !mTemplateFolder )
00938     return;
00939 
00940   mTemplateMenu->popupMenu()->clear();
00941   for ( int idx = 0; idx<mTemplateFolder->count(); ++idx ) {
00942     KMMsgBase *mb = mTemplateFolder->getMsgBase( idx );
00943 
00944     QString subj = mb->subject();
00945     if ( subj.isEmpty() ) subj = i18n("No Subject");
00946     mTemplateMenu->popupMenu()->insertItem(
00947       KStringHandler::rsqueeze( subj.replace( "&", "&&" ) ), idx );
00948   }
00949 }
00950 
00951 //-----------------------------------------------------------------------------
00952 void KMMainWidget::slotNewFromTemplate( int id )
00953 {
00954   if ( !mTemplateFolder )
00955     return;
00956   newFromTemplate(mTemplateFolder->getMsg( id ) );
00957 }
00958 
00959 //-----------------------------------------------------------------------------
00960 void KMMainWidget::newFromTemplate( KMMessage *msg )
00961 {
00962   if ( !msg )
00963     return;
00964   KMCommand *command = new KMUseTemplateCommand( this, msg );
00965   command->start();
00966 }
00967 
00968 //-----------------------------------------------------------------------------
00969 void KMMainWidget::slotPostToML()
00970 {
00971   if ( mFolder && mFolder->isMailingListEnabled() ) {
00972     KMCommand *command = new KMMailingListPostCommand( this, mFolder );
00973     command->start();
00974   }
00975   else
00976     slotCompose();
00977 }
00978 
00979 //-----------------------------------------------------------------------------
00980 void KMMainWidget::slotFolderMailingListProperties()
00981 {
00982   if (!mFolderTree) return;
00983   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( mFolderTree->currentItem() );
00984   if ( !item ) return;
00985   KMFolder* folder = item->folder();
00986   if ( folder ) {
00987     ( new KMail::MailingListFolderPropertiesDialog( this, folder ) )->show();
00988   }
00989 }
00990 
00991 //-----------------------------------------------------------------------------
00992 void KMMainWidget::slotFolderShortcutCommand()
00993 {
00994   if (!mFolderTree) return;
00995   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( mFolderTree->currentItem() );
00996   if ( item )
00997     item->assignShortcut();
00998 }
00999 
01000 
01001 //-----------------------------------------------------------------------------
01002 void KMMainWidget::slotModifyFolder()
01003 {
01004   if (!mFolderTree) return;
01005   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( mFolderTree->currentItem() );
01006   if ( item )
01007     modifyFolder( item );
01008 }
01009 
01010 //-----------------------------------------------------------------------------
01011 void KMMainWidget::modifyFolder( KMFolderTreeItem* folderItem )
01012 {
01013   KMFolder* folder = folderItem->folder();
01014   KMFolderTree* folderTree = static_cast<KMFolderTree *>( folderItem->listView() );
01015   KMFolderDialog props( folder, folder->parent(), folderTree,
01016                         i18n("Properties of Folder %1").arg( folder->label() ) );
01017   props.exec();
01018   updateFolderMenu();
01019 }
01020 
01021 //-----------------------------------------------------------------------------
01022 void KMMainWidget::slotExpireFolder()
01023 {
01024   QString     str;
01025   bool        canBeExpired = true;
01026 
01027   if (!mFolder) return;
01028 
01029   if (!mFolder->isAutoExpire()) {
01030     canBeExpired = false;
01031   } else if (mFolder->getUnreadExpireUnits()==expireNever &&
01032          mFolder->getReadExpireUnits()==expireNever) {
01033     canBeExpired = false;
01034   }
01035 
01036   if (!canBeExpired) {
01037     str = i18n("This folder does not have any expiry options set");
01038     KMessageBox::information(this, str);
01039     return;
01040   }
01041   KConfig           *config = KMKernel::config();
01042   KConfigGroupSaver saver(config, "General");
01043 
01044   if (config->readBoolEntry("warn-before-expire", true)) {
01045     str = i18n("<qt>Are you sure you want to expire the folder <b>%1</b>?</qt>").arg(QStyleSheet::escape( mFolder->label() ));
01046     if (KMessageBox::warningContinueCancel(this, str, i18n("Expire Folder"),
01047                        i18n("&Expire"))
01048     != KMessageBox::Continue) return;
01049   }
01050 
01051   mFolder->expireOldMessages( true /*immediate*/);
01052 }
01053 
01054 //-----------------------------------------------------------------------------
01055 void KMMainWidget::slotEmptyFolder()
01056 {
01057   QString str;
01058 
01059   if (!mFolder) return;
01060   bool isTrash = kmkernel->folderIsTrash(mFolder);
01061 
01062   if (mConfirmEmpty)
01063   {
01064     QString title = (isTrash) ? i18n("Empty Trash") : i18n("Move to Trash");
01065     QString text = (isTrash) ?
01066       i18n("Are you sure you want to empty the trash folder?") :
01067       i18n("<qt>Are you sure you want to move all messages from "
01068            "folder <b>%1</b> to the trash?</qt>").arg( QStyleSheet::escape( mFolder->label() ) );
01069 
01070     if (KMessageBox::warningContinueCancel(this, text, title, KGuiItem( title, "edittrash"))
01071       != KMessageBox::Continue) return;
01072   }
01073   KCursorSaver busy(KBusyPtr::busy());
01074   slotMarkAll();
01075   if (isTrash) {
01076     /* Don't ask for confirmation again when deleting, the user has already
01077        confirmed. */
01078     slotDeleteMsg( false );
01079   }
01080   else
01081     slotTrashMsg();
01082 
01083   if (mMsgView) mMsgView->clearCache();
01084 
01085   if ( !isTrash )
01086     BroadcastStatus::instance()->setStatusMsg(i18n("Moved all messages to the trash"));
01087 
01088   updateMessageActions();
01089 
01090   // Disable empty trash/move all to trash action - we've just deleted/moved all folder
01091   // contents.
01092   mEmptyFolderAction->setEnabled( false );
01093 }
01094 
01095 
01096 //-----------------------------------------------------------------------------
01097 void KMMainWidget::slotRemoveFolder()
01098 {
01099   QString str;
01100   QDir dir;
01101 
01102   if ( !mFolder ) return;
01103   if ( mFolder->isSystemFolder() ) return;
01104   if ( mFolder->isReadOnly() ) return;
01105 
01106   QString title;
01107   if ( mFolder->folderType() == KMFolderTypeSearch ) {
01108     title = i18n("Delete Search");
01109     str = i18n("<qt>Are you sure you want to delete the search <b>%1</b>?<br>"
01110                 "Any messages it shows will still be available in their original folder.</qt>")
01111            .arg( QStyleSheet::escape( mFolder->label() ) );
01112   } else {
01113     title = i18n("Delete Folder");
01114     if ( mFolder->count() == 0 ) {
01115       if ( !mFolder->child() || mFolder->child()->isEmpty() ) {
01116         str = i18n("<qt>Are you sure you want to delete the empty folder "
01117                    "<b>%1</b>?</qt>")
01118               .arg( QStyleSheet::escape( mFolder->label() ) );
01119       }
01120       else {
01121         str = i18n("<qt>Are you sure you want to delete the empty folder "
01122                    "<b>%1</b> and all its subfolders? Those subfolders might "
01123                    "not be empty and their contents will be discarded as well. "
01124                    "<p><b>Beware</b> that discarded messages are not saved "
01125                    "into your Trash folder and are permanently deleted.</qt>")
01126               .arg( QStyleSheet::escape( mFolder->label() ) );
01127       }
01128     } else {
01129       if ( !mFolder->child() || mFolder->child()->isEmpty() ) {
01130         str = i18n("<qt>Are you sure you want to delete the folder "
01131                    "<b>%1</b>, discarding its contents? "
01132                    "<p><b>Beware</b> that discarded messages are not saved "
01133                    "into your Trash folder and are permanently deleted.</qt>")
01134               .arg( QStyleSheet::escape( mFolder->label() ) );
01135       }
01136       else {
01137         str = i18n("<qt>Are you sure you want to delete the folder <b>%1</b> "
01138                    "and all its subfolders, discarding their contents? "
01139                    "<p><b>Beware</b> that discarded messages are not saved "
01140                    "into your Trash folder and are permanently deleted.</qt>")
01141             .arg( QStyleSheet::escape( mFolder->label() ) );
01142       }
01143     }
01144   }
01145 
01146   if (KMessageBox::warningContinueCancel(this, str, title,
01147                                          KGuiItem( i18n("&Delete"), "editdelete"))
01148       == KMessageBox::Continue)
01149   {
01150     if ( mFolder->hasAccounts() ) {
01151       // this folder has an account, so we need to change that to the inbox
01152       for ( AccountList::Iterator it (mFolder->acctList()->begin() ),
01153              end( mFolder->acctList()->end() ); it != end; ++it ) {
01154         (*it)->setFolder( kmkernel->inboxFolder() );
01155         KMessageBox::information(this,
01156             i18n("<qt>The folder you deleted was associated with the account "
01157               "<b>%1</b> which delivered mail into it. The folder the account "
01158               "delivers new mail into was reset to the main Inbox folder.</qt>").arg( (*it)->name()));
01159       }
01160     }
01161     if (mFolder->folderType() == KMFolderTypeImap)
01162       kmkernel->imapFolderMgr()->remove(mFolder);
01163     else if (mFolder->folderType() == KMFolderTypeCachedImap) {
01164       // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2)
01165       KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( mFolder->storage() );
01166       KMAcctCachedImap* acct = storage->account();
01167       if ( acct )
01168         acct->addDeletedFolder( mFolder );
01169 
01170       kmkernel->dimapFolderMgr()->remove(mFolder);
01171     }
01172     else if (mFolder->folderType() == KMFolderTypeSearch)
01173       kmkernel->searchFolderMgr()->remove(mFolder);
01174     else
01175       kmkernel->folderMgr()->remove(mFolder);
01176   }
01177 }
01178 
01179 //-----------------------------------------------------------------------------
01180 void KMMainWidget::slotMarkAllAsRead()
01181 {
01182   if (!mFolder)
01183     return;
01184   mFolder->markUnreadAsRead();
01185 }
01186 
01187 //-----------------------------------------------------------------------------
01188 void KMMainWidget::slotCompactFolder()
01189 {
01190   if (mFolder) {
01191     int idx = mHeaders->currentItemIndex();
01192     KCursorSaver busy(KBusyPtr::busy());
01193     mFolder->compact( KMFolder::CompactNow );
01194     // setCurrentItemByIndex will override the statusbar message, so save/restore it
01195     QString statusMsg = BroadcastStatus::instance()->statusMsg();
01196     mHeaders->setCurrentItemByIndex(idx);
01197     BroadcastStatus::instance()->setStatusMsg( statusMsg );
01198   }
01199 }
01200 
01201 
01202 //-----------------------------------------------------------------------------
01203 void KMMainWidget::slotRefreshFolder()
01204 {
01205   if (mFolder)
01206   {
01207     if ( mFolder->folderType() == KMFolderTypeImap || mFolder->folderType() == KMFolderTypeCachedImap ) {
01208       if ( !kmkernel->askToGoOnline() ) {
01209         return;
01210       }
01211     }
01212 
01213     if (mFolder->folderType() == KMFolderTypeImap)
01214     {
01215       KMFolderImap *imap = static_cast<KMFolderImap*>(mFolder->storage());
01216       imap->getAndCheckFolder();
01217     } else if ( mFolder->folderType() == KMFolderTypeCachedImap ) {
01218       KMFolderCachedImap* f = static_cast<KMFolderCachedImap*>( mFolder->storage() );
01219       f->account()->processNewMailSingleFolder( mFolder );
01220     }
01221   }
01222 }
01223 
01224 void KMMainWidget::slotTroubleshootFolder()
01225 {
01226   if (mFolder)
01227   {
01228     if ( mFolder->folderType() == KMFolderTypeCachedImap ) {
01229       KMFolderCachedImap* f = static_cast<KMFolderCachedImap*>( mFolder->storage() );
01230       f->slotTroubleshoot();
01231     }
01232   }
01233 }
01234 
01235 void KMMainWidget::slotInvalidateIMAPFolders() {
01236   if ( KMessageBox::warningContinueCancel( this,
01237           i18n("Are you sure you want to refresh the IMAP cache?\n"
01238            "This will remove all changes that you have done "
01239            "locally to your IMAP folders."),
01240       i18n("Refresh IMAP Cache"), i18n("&Refresh") ) == KMessageBox::Continue )
01241     kmkernel->acctMgr()->invalidateIMAPFolders();
01242 }
01243 
01244 //-----------------------------------------------------------------------------
01245 void KMMainWidget::slotExpireAll() {
01246   KConfig    *config = KMKernel::config();
01247   int        ret = 0;
01248 
01249   KConfigGroupSaver saver(config, "General");
01250 
01251   if (config->readBoolEntry("warn-before-expire", true)) {
01252     ret = KMessageBox::warningContinueCancel(KMainWindow::memberList->first(),
01253              i18n("Are you sure you want to expire all old messages?"),
01254              i18n("Expire Old Messages?"), i18n("Expire"));
01255     if (ret != KMessageBox::Continue) {
01256       return;
01257     }
01258   }
01259 
01260   kmkernel->expireAllFoldersNow();
01261 }
01262 
01263 //-----------------------------------------------------------------------------
01264 void KMMainWidget::slotCompactAll()
01265 {
01266   KCursorSaver busy(KBusyPtr::busy());
01267   kmkernel->compactAllFolders();
01268 }
01269 
01270 
01271 //-----------------------------------------------------------------------------
01272 void KMMainWidget::slotOverrideHtml()
01273 {
01274   if( mHtmlPref == mFolderHtmlPref ) {
01275     int result = KMessageBox::warningContinueCancel( this,
01276       // the warning text is taken from configuredialog.cpp:
01277       i18n( "Use of HTML in mail will make you more vulnerable to "
01278         "\"spam\" and may increase the likelihood that your system will be "
01279         "compromised by other present and anticipated security exploits." ),
01280       i18n( "Security Warning" ),
01281       i18n( "Use HTML" ),
01282       "OverrideHtmlWarning", false);
01283     if( result == KMessageBox::Cancel ) {
01284       mPreferHtmlAction->setChecked( false );
01285       return;
01286     }
01287   }
01288   mFolderHtmlPref = !mFolderHtmlPref;
01289   if (mMsgView) {
01290     mMsgView->setHtmlOverride(mFolderHtmlPref);
01291     mMsgView->update( true );
01292   }
01293 }
01294 
01295 //-----------------------------------------------------------------------------
01296 void KMMainWidget::slotOverrideHtmlLoadExt()
01297 {
01298   if( mHtmlLoadExtPref == mFolderHtmlLoadExtPref ) {
01299     int result = KMessageBox::warningContinueCancel( this,
01300       // the warning text is taken from configuredialog.cpp:
01301       i18n( "Loading external references in html mail will make you more vulnerable to "
01302         "\"spam\" and may increase the likelihood that your system will be "
01303         "compromised by other present and anticipated security exploits." ),
01304       i18n( "Security Warning" ),
01305       i18n( "Load External References" ),
01306       "OverrideHtmlLoadExtWarning", false);
01307     if( result == KMessageBox::Cancel ) {
01308       mPreferHtmlLoadExtAction->setChecked( false );
01309       return;
01310     }
01311   }
01312   mFolderHtmlLoadExtPref = !mFolderHtmlLoadExtPref;
01313   if (mMsgView) {
01314     mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref);
01315     mMsgView->update( true );
01316   }
01317 }
01318 
01319 //-----------------------------------------------------------------------------
01320 void KMMainWidget::slotOverrideThread()
01321 {
01322   mFolderThreadPref = !mFolderThreadPref;
01323   mHeaders->setNestedOverride(mFolderThreadPref);
01324   mThreadBySubjectAction->setEnabled(mThreadMessagesAction->isChecked());
01325 }
01326 
01327 //-----------------------------------------------------------------------------
01328 void KMMainWidget::slotToggleSubjectThreading()
01329 {
01330   mFolderThreadSubjPref = !mFolderThreadSubjPref;
01331   mHeaders->setSubjectThreading(mFolderThreadSubjPref);
01332 }
01333 
01334 //-----------------------------------------------------------------------------
01335 void KMMainWidget::slotToggleShowQuickSearch()
01336 {
01337   GlobalSettings::self()->setQuickSearchActive( !GlobalSettings::self()->quickSearchActive() );
01338   if ( GlobalSettings::self()->quickSearchActive() )
01339     mSearchToolBar->show();
01340   else {
01341     mQuickSearchLine->reset();
01342     mSearchToolBar->hide();
01343   }
01344 }
01345 
01346 //-----------------------------------------------------------------------------
01347 void KMMainWidget::slotMessageQueuedOrDrafted()
01348 {
01349   if (!kmkernel->folderIsDraftOrOutbox(mFolder))
01350       return;
01351   if (mMsgView)
01352     mMsgView->update(true);
01353 }
01354 
01355 
01356 //-----------------------------------------------------------------------------
01357 void KMMainWidget::slotForwardInlineMsg()
01358 {
01359   KMMessageList* selected = mHeaders->selectedMsgs();
01360   KMCommand *command = 0L;
01361   if(selected && !selected->isEmpty()) {
01362     command = new KMForwardInlineCommand( this, *selected,
01363                                           mFolder->identity() );
01364   } else {
01365     command = new KMForwardInlineCommand( this, mHeaders->currentMsg(),
01366                                           mFolder->identity() );
01367   }
01368 
01369   command->start();
01370 }
01371 
01372 
01373 //-----------------------------------------------------------------------------
01374 void KMMainWidget::slotForwardAttachedMsg()
01375 {
01376   KMMessageList* selected = mHeaders->selectedMsgs();
01377   KMCommand *command = 0L;
01378   if(selected && !selected->isEmpty()) {
01379     command = new KMForwardAttachedCommand( this, *selected, mFolder->identity() );
01380   } else {
01381     command = new KMForwardAttachedCommand( this, mHeaders->currentMsg(), mFolder->identity() );
01382   }
01383 
01384   command->start();
01385 }
01386 
01387 //-----------------------------------------------------------------------------
01388 void KMMainWidget::slotForwardDigestMsg()
01389 {
01390   KMMessageList* selected = mHeaders->selectedMsgs();
01391   KMCommand *command = 0L;
01392   if(selected && !selected->isEmpty()) {
01393     command = new KMForwardDigestCommand( this, *selected, mFolder->identity() );
01394   } else {
01395     command = new KMForwardDigestCommand( this, mHeaders->currentMsg(), mFolder->identity() );
01396   }
01397 
01398   command->start();
01399 }
01400 
01401 //-----------------------------------------------------------------------------
01402 void KMMainWidget::slotEditMsg()
01403 {
01404   KMCommand *command = new KMEditMsgCommand( this, mHeaders->currentMsg() );
01405   command->start();
01406 }
01407 
01408 //-----------------------------------------------------------------------------
01409 void KMMainWidget::slotUseTemplate()
01410 {
01411   newFromTemplate( mHeaders->currentMsg() );
01412 }
01413 
01414 //-----------------------------------------------------------------------------
01415 void KMMainWidget::slotResendMsg()
01416 {
01417   KMCommand *command = new KMResendMessageCommand( this, mHeaders->currentMsg() );
01418   command->start();
01419 }
01420 
01421 
01422 //-----------------------------------------------------------------------------
01423 void KMMainWidget::slotTrashMsg()
01424 {
01425   mHeaders->deleteMsg();
01426 }
01427 
01428 //-----------------------------------------------------------------------------
01429 void KMMainWidget::slotDeleteMsg( bool confirmDelete )
01430 {
01431   mHeaders->moveMsgToFolder( 0, confirmDelete );
01432 }
01433 
01434 //-----------------------------------------------------------------------------
01435 void KMMainWidget::slotTrashThread()
01436 {
01437   mHeaders->highlightCurrentThread();
01438   mHeaders->deleteMsg();
01439 }
01440 
01441 //-----------------------------------------------------------------------------
01442 void KMMainWidget::slotDeleteThread( bool confirmDelete )
01443 {
01444   mHeaders->highlightCurrentThread();
01445   mHeaders->moveMsgToFolder( 0, confirmDelete );
01446 }
01447 
01448 //-----------------------------------------------------------------------------
01449 void KMMainWidget::slotReplyToMsg()
01450 {
01451   QString text = mMsgView? mMsgView->copyText() : "";
01452   KMCommand *command = new KMReplyToCommand( this, mHeaders->currentMsg(), text );
01453   command->start();
01454 }
01455 
01456 
01457 //-----------------------------------------------------------------------------
01458 void KMMainWidget::slotReplyAuthorToMsg()
01459 {
01460   QString text = mMsgView? mMsgView->copyText() : "";
01461   KMCommand *command = new KMReplyAuthorCommand( this, mHeaders->currentMsg(), text );
01462   command->start();
01463 }
01464 
01465 
01466 //-----------------------------------------------------------------------------
01467 void KMMainWidget::slotReplyAllToMsg()
01468 {
01469   QString text = mMsgView? mMsgView->copyText() : "";
01470   KMCommand *command = new KMReplyToAllCommand( this, mHeaders->currentMsg(), text );
01471   command->start();
01472 }
01473 
01474 
01475 //-----------------------------------------------------------------------------
01476 void KMMainWidget::slotRedirectMsg()
01477 {
01478   KMCommand *command = new KMRedirectCommand( this, mHeaders->currentMsg() );
01479   command->start();
01480 }
01481 
01482 //-----------------------------------------------------------------------------
01483 void KMMainWidget::slotReplyListToMsg()
01484 {
01485 
01486   QString text = mMsgView? mMsgView->copyText() : "";
01487   KMCommand *command = new KMReplyListCommand( this, mHeaders->currentMsg(),
01488                            text );
01489   command->start();
01490 }
01491 
01492 
01493 //-----------------------------------------------------------------------------
01494 void KMMainWidget::slotCustomReplyToMsg( int tid )
01495 {
01496   QString text = mMsgView? mMsgView->copyText() : "";
01497   QString tmpl = mCustomTemplates[ tid ];
01498   kdDebug() << "Reply with template: " << tmpl << " (" << tid << ")" << endl;
01499   KMCommand *command = new KMCustomReplyToCommand( this,
01500                                                    mHeaders->currentMsg(),
01501                                                    text,
01502                                                    tmpl );
01503   command->start();
01504 }
01505 
01506 
01507 //-----------------------------------------------------------------------------
01508 void KMMainWidget::slotCustomReplyAllToMsg( int tid )
01509 {
01510   QString text = mMsgView? mMsgView->copyText() : "";
01511   QString tmpl = mCustomTemplates[ tid ];
01512   kdDebug() << "Reply to All with template: " << tmpl << " (" << tid << ")" << endl;
01513   KMCommand *command = new KMCustomReplyAllToCommand( this,
01514                                                    mHeaders->currentMsg(),
01515                                                    text,
01516                                                    tmpl );
01517   command->start();
01518 }
01519 
01520 
01521 //-----------------------------------------------------------------------------
01522 void KMMainWidget::slotCustomForwardMsg( int tid )
01523 {
01524   QString tmpl = mCustomTemplates[ tid ];
01525   kdDebug() << "Forward with template: " << tmpl << " (" << tid << ")" << endl;
01526   KMMessageList* selected = mHeaders->selectedMsgs();
01527   KMCommand *command = 0L;
01528   if(selected && !selected->isEmpty()) {
01529     command = new KMCustomForwardCommand( this, *selected,
01530                                           mFolder->identity(), tmpl );
01531   } else {
01532     command = new KMCustomForwardCommand( this, mHeaders->currentMsg(),
01533                                           mFolder->identity(), tmpl );
01534   }
01535   command->start();
01536 }
01537 
01538 
01539 //-----------------------------------------------------------------------------
01540 void KMMainWidget::slotNoQuoteReplyToMsg()
01541 {
01542   KMCommand *command = new KMNoQuoteReplyToCommand( this, mHeaders->currentMsg() );
01543   command->start();
01544 }
01545 
01546 //-----------------------------------------------------------------------------
01547 void KMMainWidget::slotSubjectFilter()
01548 {
01549   KMMessage *msg = mHeaders->currentMsg();
01550   if (!msg)
01551     return;
01552 
01553   KMCommand *command = new KMFilterCommand( "Subject", msg->subject() );
01554   command->start();
01555 }
01556 
01557 //-----------------------------------------------------------------------------
01558 void KMMainWidget::slotMailingListFilter()
01559 {
01560   KMMessage *msg = mHeaders->currentMsg();
01561   if (!msg)
01562     return;
01563 
01564   KMCommand *command = new KMMailingListFilterCommand( this, msg );
01565   command->start();
01566 }
01567 
01568 //-----------------------------------------------------------------------------
01569 void KMMainWidget::slotFromFilter()
01570 {
01571   KMMessage *msg = mHeaders->currentMsg();
01572   if (!msg)
01573     return;
01574 
01575   AddrSpecList al = msg->extractAddrSpecs( "From" );
01576   KMCommand *command;
01577   if ( al.empty() )
01578     command = new KMFilterCommand( "From",  msg->from() );
01579   else
01580     command = new KMFilterCommand( "From",  al.front().asString() );
01581   command->start();
01582 }
01583 
01584 //-----------------------------------------------------------------------------
01585 void KMMainWidget::slotToFilter()
01586 {
01587   KMMessage *msg = mHeaders->currentMsg();
01588   if (!msg)
01589     return;
01590 
01591   KMCommand *command = new KMFilterCommand( "To",  msg->to() );
01592   command->start();
01593 }
01594 
01595 //-----------------------------------------------------------------------------
01596 void KMMainWidget::updateListFilterAction()
01597 {
01598   //Proxy the mListFilterAction to update the action text
01599   QCString name;
01600   QString value;
01601   QString lname = MailingList::name( mHeaders->currentMsg(), name, value );
01602   mListFilterAction->setText( i18n("Filter on Mailing-List...") );
01603   if ( lname.isNull() )
01604     mListFilterAction->setEnabled( false );
01605   else {
01606     mListFilterAction->setEnabled( true );
01607     mListFilterAction->setText( i18n( "Filter on Mailing-List %1..." ).arg( lname ) );
01608   }
01609 }
01610 
01611 
01612 //-----------------------------------------------------------------------------
01613 void KMMainWidget::slotUndo()
01614 {
01615     mHeaders->undo();
01616     updateMessageActions();
01617 }
01618 
01619 //-----------------------------------------------------------------------------
01620 void KMMainWidget::slotToggleUnread()
01621 {
01622   mFolderTree->toggleColumn(KMFolderTree::unread);
01623 }
01624 
01625 //-----------------------------------------------------------------------------
01626 void KMMainWidget::slotToggleTotalColumn()
01627 {
01628   mFolderTree->toggleColumn(KMFolderTree::total, true);
01629 }
01630 
01631 //-----------------------------------------------------------------------------
01632 void KMMainWidget::slotJumpToFolder()
01633 {
01634   KMail::KMFolderSelDlg dlg( this, i18n("Jump to Folder"), true );
01635   KMFolder* dest;
01636 
01637   if (!dlg.exec()) return;
01638   if (!(dest = dlg.folder())) return;
01639 
01640   slotSelectFolder( dest );
01641 }
01642 
01643 //-----------------------------------------------------------------------------
01644 void KMMainWidget::slotMoveMsg()
01645 {
01646   KMail::KMFolderSelDlg dlg( this, i18n("Move Message to Folder"), true );
01647   KMFolder* dest;
01648 
01649   if (!dlg.exec()) return;
01650   if (!(dest = dlg.folder())) return;
01651 
01652   mHeaders->moveMsgToFolder(dest);
01653 }
01654 
01655 //-----------------------------------------------------------------------------
01656 void KMMainWidget::slotMoveMsgToFolder( KMFolder *dest)
01657 {
01658   mHeaders->moveMsgToFolder(dest);
01659 }
01660 
01661 //-----------------------------------------------------------------------------
01662 void KMMainWidget::slotCopyMsgToFolder( KMFolder *dest)
01663 {
01664   mHeaders->copyMsgToFolder(dest);
01665 }
01666 
01667 //-----------------------------------------------------------------------------
01668 void KMMainWidget::slotApplyFilters()
01669 {
01670   mHeaders->applyFiltersOnMsg();
01671 }
01672 
01673 //-----------------------------------------------------------------------------
01674 void KMMainWidget::slotEditVacation()
01675 {
01676   if ( !kmkernel->askToGoOnline() ) {
01677     return;
01678   }
01679 
01680   if ( mVacation )
01681     return;
01682 
01683   mVacation = new Vacation( this );
01684   if ( mVacation->isUsable() ) {
01685     connect( mVacation, SIGNAL(result(bool)), mVacation, SLOT(deleteLater()) );
01686   } else {
01687     QString msg = i18n("KMail's Out of Office Reply functionality relies on "
01688                       "server-side filtering. You have not yet configured an "
01689                       "IMAP server for this.\n"
01690                       "You can do this on the \"Filtering\" tab of the IMAP "
01691                       "account configuration.");
01692     KMessageBox::sorry( this, msg, i18n("No Server-Side Filtering Configured") );
01693 
01694     delete mVacation; // QGuardedPtr sets itself to 0!
01695   }
01696 }
01697 
01698 //-----------------------------------------------------------------------------
01699 void KMMainWidget::slotDebugSieve()
01700 {
01701 #if !defined(NDEBUG)
01702   if ( mSieveDebugDialog )
01703     return;
01704 
01705   mSieveDebugDialog = new SieveDebugDialog( this );
01706   mSieveDebugDialog->exec();
01707   delete mSieveDebugDialog;
01708 #endif
01709 }
01710 
01711 //-----------------------------------------------------------------------------
01712 void KMMainWidget::slotStartCertManager()
01713 {
01714   KProcess certManagerProc; // save to create on the heap, since
01715   // there is no parent
01716   certManagerProc << "kleopatra";
01717 
01718   if( !certManagerProc.start( KProcess::DontCare ) )
01719     KMessageBox::error( this, i18n( "Could not start certificate manager; "
01720                                     "please check your installation." ),
01721                                     i18n( "KMail Error" ) );
01722   else
01723     kdDebug(5006) << "\nslotStartCertManager(): certificate manager started.\n" << endl;
01724   // process continues to run even after the KProcess object goes
01725   // out of scope here, since it is started in DontCare run mode.
01726 
01727 }
01728 
01729 //-----------------------------------------------------------------------------
01730 void KMMainWidget::slotStartWatchGnuPG()
01731 {
01732   KProcess certManagerProc;
01733   certManagerProc << "kwatchgnupg";
01734 
01735   if( !certManagerProc.start( KProcess::DontCare ) )
01736     KMessageBox::error( this, i18n( "Could not start GnuPG LogViewer (kwatchgnupg); "
01737                                     "please check your installation." ),
01738                                     i18n( "KMail Error" ) );
01739 }
01740 
01741 //-----------------------------------------------------------------------------
01742 void KMMainWidget::slotCopyMsg()
01743 {
01744   KMail::KMFolderSelDlg dlg( this, i18n("Copy Message to Folder"), true );
01745   KMFolder* dest;
01746 
01747   if (!dlg.exec()) return;
01748   if (!(dest = dlg.folder())) return;
01749 
01750   mHeaders->copyMsgToFolder(dest);
01751 }
01752 
01753 //-----------------------------------------------------------------------------
01754 void KMMainWidget::slotPrintMsg()
01755 {
01756   bool htmlOverride = mMsgView ? mMsgView->htmlOverride() : false;
01757   bool htmlLoadExtOverride = mMsgView ? mMsgView->htmlLoadExtOverride() : false;
01758   KConfigGroup reader( KMKernel::config(), "Reader" );
01759   bool useFixedFont = mMsgView ? mMsgView->isFixedFont()
01760                                : reader.readBoolEntry( "useFixedFont", false );
01761   KMCommand *command =
01762     new KMPrintCommand( this, mHeaders->currentMsg(),
01763                         htmlOverride, htmlLoadExtOverride,
01764                         useFixedFont, overrideEncoding() );
01765   command->start();
01766 }
01767 
01768 //-----------------------------------------------------------------------------
01769 void KMMainWidget::slotConfigChanged()
01770 {
01771   readConfig();
01772 }
01773 
01774 //-----------------------------------------------------------------------------
01775 void KMMainWidget::slotSaveMsg()
01776 {
01777   KMMessage *msg = mHeaders->currentMsg();
01778   if (!msg)
01779     return;
01780   KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( this,
01781     *mHeaders->selectedMsgs() );
01782 
01783   if (saveCommand->url().isEmpty())
01784     delete saveCommand;
01785   else
01786     saveCommand->start();
01787 }
01788 
01789 //-----------------------------------------------------------------------------
01790 void KMMainWidget::slotOpenMsg()
01791 {
01792   KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( this, 0, overrideEncoding() );
01793 
01794   openCommand->start();
01795 }
01796 
01797 //-----------------------------------------------------------------------------
01798 void KMMainWidget::slotSaveAttachments()
01799 {
01800   KMMessage *msg = mHeaders->currentMsg();
01801   if (!msg)
01802     return;
01803   KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand( this,
01804                                                                         *mHeaders->selectedMsgs() );
01805   saveCommand->start();
01806 }
01807 
01808 void KMMainWidget::slotOnlineStatus()
01809 {
01810   // KMKernel will emit a signal when we toggle the network state that is caught by
01811   // KMMainWidget::slotUpdateOnlineStatus to update our GUI
01812   if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online ) {
01813     // if online; then toggle and set it offline.
01814     kmkernel->stopNetworkJobs();
01815   } else {
01816     kmkernel->resumeNetworkJobs();
01817   }
01818 }
01819 
01820 void KMMainWidget::slotUpdateOnlineStatus( GlobalSettings::EnumNetworkState::type )
01821 {
01822   if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online )
01823     actionCollection()->action( "online_status" )->setText( i18n("Work Offline") );
01824   else
01825     actionCollection()->action( "online_status" )->setText( i18n("Work Online") );
01826 }
01827 
01828 
01829 //-----------------------------------------------------------------------------
01830 void KMMainWidget::slotSendQueued()
01831 {
01832   if ( !kmkernel->askToGoOnline() ) {
01833     return;
01834   }
01835 
01836   kmkernel->msgSender()->sendQueued();
01837 }
01838 
01839 //-----------------------------------------------------------------------------
01840 void KMMainWidget::slotSendQueuedVia( int item )
01841 {
01842   if ( !kmkernel->askToGoOnline() ) {
01843     return;
01844   }
01845 
01846   QStringList availTransports= KMail::TransportManager::transportNames();
01847   QString customTransport = availTransports[ item ];
01848 
01849   kmkernel->msgSender()->sendQueued( customTransport );
01850 }
01851 
01852 //-----------------------------------------------------------------------------
01853 void KMMainWidget::slotViewChange()
01854 {
01855   if(mBodyPartsMenu->isItemChecked(mBodyPartsMenu->idAt(0)))
01856   {
01857     mBodyPartsMenu->setItemChecked(mBodyPartsMenu->idAt(0),FALSE);
01858     mBodyPartsMenu->setItemChecked(mBodyPartsMenu->idAt(1),TRUE);
01859   }
01860   else if(mBodyPartsMenu->isItemChecked(mBodyPartsMenu->idAt(1)))
01861   {
01862     mBodyPartsMenu->setItemChecked(mBodyPartsMenu->idAt(1),FALSE);
01863     mBodyPartsMenu->setItemChecked(mBodyPartsMenu->idAt(0),TRUE);
01864   }
01865 
01866   //mMsgView->setInline(!mMsgView->isInline());
01867 }
01868 
01869 
01870 //-----------------------------------------------------------------------------
01871 void KMMainWidget::folderSelectedUnread( KMFolder* aFolder )
01872 {
01873   folderSelected( aFolder, true );
01874   slotChangeCaption( mFolderTree->currentItem() );
01875 }
01876 
01877 void KMMainWidget::openFolder()
01878 {
01879   if ( !mFolder || mFolder->folderType() != KMFolderTypeImap )
01880     return;
01881   KMFolderImap *imap = static_cast<KMFolderImap*>(mFolder->storage());
01882   assert( !mOpenedImapFolder );
01883   imap->open("mainwidget"); // will be closed in the folderSelected slot
01884   mOpenedImapFolder = true;
01885   // first get new headers before we select the folder
01886   imap->setSelected( true );
01887 }
01888 
01889 void KMMainWidget::closeFolder()
01890 {
01891   if ( !mFolder || mFolder->folderType() != KMFolderTypeImap )
01892     return;
01893   assert( mOpenedImapFolder );
01894   KMFolderImap *imap = static_cast<KMFolderImap*>(mFolder->storage());
01895   imap->setSelected( false );
01896   mFolder->close( "mainwidget" );
01897   mOpenedImapFolder = false;
01898 }
01899 
01900 //-----------------------------------------------------------------------------
01901 void KMMainWidget::folderSelected()
01902 {
01903   folderSelected( mFolder );
01904   updateFolderMenu();
01905 }
01906 
01907 //-----------------------------------------------------------------------------
01908 void KMMainWidget::folderSelected( KMFolder* aFolder, bool forceJumpToUnread )
01909 {
01910   KCursorSaver busy(KBusyPtr::busy());
01911 
01912   if (mMsgView)
01913     mMsgView->clear(true);
01914 
01915   if ( mFolder && mFolder->folderType() == KMFolderTypeImap && !mFolder->noContent() )
01916   {
01917     KMFolderImap *imap = static_cast<KMFolderImap*>(mFolder->storage());
01918     if ( mFolder->needsCompacting() && imap->autoExpunge() )
01919       imap->expungeFolder(imap, TRUE);
01920   }
01921 
01922   // Re-enable the msg list and quicksearch if we're showing a splash
01923   // screen. This is true either if there's no active folder, or if we
01924   // have a timer that is no longer active (i.e. it has already fired)
01925   // To make the if() a bit more complicated, we suppress the hiding
01926   // when the new folder is also an IMAP folder, because that's an
01927   // async operation and we don't want flicker if it results in just
01928   // a new splash.
01929   bool newFolder = ( (KMFolder*)mFolder != aFolder );
01930   bool isNewImapFolder = aFolder && aFolder->folderType() == KMFolderTypeImap && newFolder;
01931   if( !mFolder
01932       || ( !isNewImapFolder && mShowBusySplashTimer )
01933       || ( newFolder && mShowingOfflineScreen && !( isNewImapFolder && kmkernel->isOffline() ) ) ) {
01934     if ( mMsgView ) {
01935       mMsgView->enableMsgDisplay();
01936       mMsgView->clear( true );
01937     }
01938     if( mSearchAndHeaders && mHeaders )
01939       mSearchAndHeaders->show();
01940     mShowingOfflineScreen = false;
01941   }
01942 
01943   // Delete any pending timer, if needed it will be recreated below
01944   delete mShowBusySplashTimer;
01945   mShowBusySplashTimer = 0;
01946 
01947   if ( newFolder )
01948     writeFolderConfig();
01949   if ( mFolder ) {
01950     disconnect( mFolder, SIGNAL( changed() ),
01951            this, SLOT( updateMarkAsReadAction() ) );
01952     disconnect( mFolder, SIGNAL( msgHeaderChanged( KMFolder*, int ) ),
01953            this, SLOT( updateMarkAsReadAction() ) );
01954     disconnect( mFolder, SIGNAL( msgAdded( int ) ),
01955            this, SLOT( updateMarkAsReadAction() ) );
01956     disconnect( mFolder, SIGNAL( msgRemoved( KMFolder * ) ),
01957            this, SLOT( updateMarkAsReadAction() ) );
01958   }
01959 
01960   if ( newFolder )
01961       closeFolder();
01962 
01963   mFolder = aFolder;
01964 
01965   if ( newFolder )
01966     openFolder();
01967 
01968   if ( aFolder && aFolder->folderType() == KMFolderTypeImap )
01969   {
01970     if ( kmkernel->isOffline() ) {
01971       showOfflinePage();
01972       return;
01973     }
01974     KMFolderImap *imap = static_cast<KMFolderImap*>(aFolder->storage());
01975     if ( newFolder && !mFolder->noContent() )
01976     {
01977       connect( imap, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
01978           this, SLOT( folderSelected() ) );
01979       imap->getAndCheckFolder();
01980       mHeaders->setFolder( 0 );
01981       updateFolderMenu();
01982       mForceJumpToUnread = forceJumpToUnread;
01983 
01984       // Set a timer to show a splash screen if fetching folder contents
01985       // takes more than the amount of seconds configured in the kmailrc (default 1000 msec)
01986       mShowBusySplashTimer = new QTimer( this );
01987       connect( mShowBusySplashTimer, SIGNAL( timeout() ), this, SLOT( slotShowBusySplash() ) );
01988       mShowBusySplashTimer->start( GlobalSettings::self()->folderLoadingTimeout(), true );
01989       return;
01990     } else {
01991       // the folder is complete now - so go ahead
01992       disconnect( imap, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
01993           this, SLOT( folderSelected() ) );
01994       forceJumpToUnread = mForceJumpToUnread;
01995     }
01996   }
01997 
01998   if ( mFolder ) { // == 0 -> pointing to toplevel ("Welcome to KMail") folder
01999     connect( mFolder, SIGNAL( changed() ),
02000            this, SLOT( updateMarkAsReadAction() ) );
02001     connect( mFolder, SIGNAL( msgHeaderChanged( KMFolder*, int ) ),
02002            this, SLOT( updateMarkAsReadAction() ) );
02003     connect( mFolder, SIGNAL( msgAdded( int ) ),
02004            this, SLOT( updateMarkAsReadAction() ) );
02005     connect( mFolder, SIGNAL( msgRemoved(KMFolder *) ),
02006            this, SLOT( updateMarkAsReadAction() ) );
02007   }
02008   readFolderConfig();
02009   if (mMsgView)
02010   {
02011     mMsgView->setHtmlOverride(mFolderHtmlPref);
02012     mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref);
02013   }
02014   mHeaders->setFolder( mFolder, forceJumpToUnread );
02015   updateMessageActions();
02016   updateFolderMenu();
02017   if (!aFolder)
02018     slotIntro();
02019 }
02020 
02021 //-----------------------------------------------------------------------------
02022 void KMMainWidget::slotShowBusySplash()
02023 {
02024   if ( mReaderWindowActive )
02025   {
02026     mMsgView->displayBusyPage();
02027     // hide widgets that are in the way:
02028     if ( mSearchAndHeaders && mHeaders && mLongFolderList )
02029       mSearchAndHeaders->hide();
02030   }
02031 }
02032 
02033 void KMMainWidget::showOfflinePage()
02034 {
02035   if ( !mReaderWindowActive ) return;
02036   mShowingOfflineScreen = true;
02037 
02038   mMsgView->displayOfflinePage();
02039   // hide widgets that are in the way:
02040   if ( mSearchAndHeaders && mHeaders && mLongFolderList )
02041     mSearchAndHeaders->hide();
02042 }
02043 
02044 //-----------------------------------------------------------------------------
02045 void KMMainWidget::slotMsgSelected(KMMessage *msg)
02046 {
02047   if ( msg && msg->parent() && !msg->isComplete() )
02048   {
02049     if ( msg->transferInProgress() )
02050       return;
02051     mMsgView->clear();
02052     mMsgView->setWaitingForSerNum( msg->getMsgSerNum() );
02053 
02054     if ( mJob ) {
02055        disconnect( mJob, 0, mMsgView, 0 );
02056        delete mJob;
02057     }
02058     mJob = msg->parent()->createJob( msg, FolderJob::tGetMessage, 0,
02059           "STRUCTURE", mMsgView->attachmentStrategy() );
02060     connect(mJob, SIGNAL(messageRetrieved(KMMessage*)),
02061             mMsgView, SLOT(slotMessageArrived(KMMessage*)));
02062     mJob->start();
02063   } else {
02064     mMsgView->setMsg(msg);
02065   }
02066   // reset HTML override to the folder setting
02067   mMsgView->setHtmlOverride(mFolderHtmlPref);
02068   mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref);
02069 }
02070 
02071 //-----------------------------------------------------------------------------
02072 void KMMainWidget::slotMsgChanged()
02073 {
02074   mHeaders->msgChanged();
02075 }
02076 
02077 //-----------------------------------------------------------------------------
02078 void KMMainWidget::slotSelectFolder(KMFolder* folder)
02079 {
02080   QListViewItem* item = mFolderTree->indexOfFolder(folder);
02081   if ( item ) {
02082     mFolderTree->ensureItemVisible( item );
02083     mFolderTree->doFolderSelected( item );
02084   }
02085 }
02086 
02087 //-----------------------------------------------------------------------------
02088 void KMMainWidget::slotSelectMessage(KMMessage* msg)
02089 {
02090   int idx = mFolder->find(msg);
02091   if (idx != -1) {
02092     mHeaders->setCurrentMsg(idx);
02093     if (mMsgView)
02094       mMsgView->setMsg(msg);
02095   }
02096 }
02097 
02098 //-----------------------------------------------------------------------------
02099 void KMMainWidget::slotReplaceMsgByUnencryptedVersion()
02100 {
02101   kdDebug(5006) << "KMMainWidget::slotReplaceMsgByUnencryptedVersion()" << endl;
02102   KMMessage* oldMsg = mHeaders->currentMsg();
02103   if( oldMsg ) {
02104     kdDebug(5006) << "KMMainWidget  -  old message found" << endl;
02105     if( oldMsg->hasUnencryptedMsg() ) {
02106       kdDebug(5006) << "KMMainWidget  -  extra unencrypted message found" << endl;
02107       KMMessage* newMsg = oldMsg->unencryptedMsg();
02108       // adjust the message id
02109       {
02110         QString msgId( oldMsg->msgId() );
02111         QString prefix("DecryptedMsg.");
02112         int oldIdx = msgId.find(prefix, 0, false);
02113         if( -1 == oldIdx ) {
02114           int leftAngle = msgId.findRev( '<' );
02115           msgId = msgId.insert( (-1 == leftAngle) ? 0 : ++leftAngle, prefix );
02116         }
02117         else {
02118           // toggle between "DecryptedMsg." and "DeCryptedMsg."
02119           // to avoid same message id
02120           QCharRef c = msgId[ oldIdx+2 ];
02121           if( 'C' == c )
02122             c = 'c';
02123           else
02124             c = 'C';
02125         }
02126         newMsg->setMsgId( msgId );
02127         mMsgView->setIdOfLastViewedMessage( msgId );
02128       }
02129       // insert the unencrypted message
02130       kdDebug(5006) << "KMMainWidget  -  adding unencrypted message to folder" << endl;
02131       mFolder->addMsg( newMsg );
02132       /* Figure out its index in the folder for selecting. This must be count()-1,
02133        * since we append. Be safe and do find, though, just in case. */
02134       int newMsgIdx = mFolder->find( newMsg );
02135       Q_ASSERT( newMsgIdx != -1 );
02136       /* we need this unget, to have the message displayed correctly initially */
02137       mFolder->unGetMsg( newMsgIdx );
02138       int idx = mFolder->find( oldMsg );
02139       Q_ASSERT( idx != -1 );
02140       /* only select here, so the old one is not un-Gotten before, which would
02141        * render the pointer we hold invalid so that find would fail */
02142       mHeaders->setCurrentItemByIndex( newMsgIdx );
02143       // remove the old one
02144       if ( idx != -1 ) {
02145         kdDebug(5006) << "KMMainWidget  -  deleting encrypted message" << endl;
02146         mFolder->take( idx );
02147       }
02148 
02149       kdDebug(5006) << "KMMainWidget  -  updating message actions" << endl;
02150       updateMessageActions();
02151 
02152       kdDebug(5006) << "KMMainWidget  -  done." << endl;
02153     } else
02154       kdDebug(5006) << "KMMainWidget  -  NO EXTRA UNENCRYPTED MESSAGE FOUND" << endl;
02155   } else
02156     kdDebug(5006) << "KMMainWidget  -  PANIC: NO OLD MESSAGE FOUND" << endl;
02157 }
02158 
02159 //-----------------------------------------------------------------------------
02160 void KMMainWidget::slotSetMsgStatusNew()
02161 {
02162   mHeaders->setMsgStatus(KMMsgStatusNew);
02163 }
02164 
02165 //-----------------------------------------------------------------------------
02166 void KMMainWidget::slotSetMsgStatusUnread()
02167 {
02168   mHeaders->setMsgStatus(KMMsgStatusUnread);
02169 }
02170 
02171 //-----------------------------------------------------------------------------
02172 void KMMainWidget::slotSetMsgStatusRead()
02173 {
02174   mHeaders->setMsgStatus(KMMsgStatusRead);
02175 }
02176 
02177 //-----------------------------------------------------------------------------
02178 void KMMainWidget::slotSetMsgStatusFlag()
02179 {
02180   mHeaders->setMsgStatus(KMMsgStatusFlag, true);
02181 }
02182 
02183 //-----------------------------------------------------------------------------
02184 void KMMainWidget::slotSetMsgStatusTodo()
02185 {
02186   mHeaders->setMsgStatus(KMMsgStatusTodo, true);
02187 }
02188 
02189 //-----------------------------------------------------------------------------
02190 void KMMainWidget::slotSetMsgStatusSent()
02191 {
02192   mHeaders->setMsgStatus(KMMsgStatusSent, true);
02193 }
02194 
02195 //-----------------------------------------------------------------------------
02196 void KMMainWidget::slotSetThreadStatusNew()
02197 {
02198   mHeaders->setThreadStatus(KMMsgStatusNew);
02199 }
02200 
02201 //-----------------------------------------------------------------------------
02202 void KMMainWidget::slotSetThreadStatusUnread()
02203 {
02204   mHeaders->setThreadStatus(KMMsgStatusUnread);
02205 }
02206 
02207 //-----------------------------------------------------------------------------
02208 void KMMainWidget::slotSetThreadStatusFlag()
02209 {
02210   mHeaders->setThreadStatus(KMMsgStatusFlag, true);
02211 }
02212 
02213 //-----------------------------------------------------------------------------
02214 void KMMainWidget::slotSetThreadStatusRead()
02215 {
02216   mHeaders->setThreadStatus(KMMsgStatusRead);
02217 }
02218 
02219 //-----------------------------------------------------------------------------
02220 void KMMainWidget::slotSetThreadStatusTodo()
02221 {
02222   mHeaders->setThreadStatus(KMMsgStatusTodo, true);
02223 }
02224 
02225 //-----------------------------------------------------------------------------
02226 void KMMainWidget::slotSetThreadStatusWatched()
02227 {
02228   mHeaders->setThreadStatus(KMMsgStatusWatched, true);
02229   if (mWatchThreadAction->isChecked()) {
02230     mIgnoreThreadAction->setChecked(false);
02231   }
02232 }
02233 
02234 //-----------------------------------------------------------------------------
02235 void KMMainWidget::slotSetThreadStatusIgnored()
02236 {
02237   mHeaders->setThreadStatus(KMMsgStatusIgnored, true);
02238   if (mIgnoreThreadAction->isChecked()) {
02239     mWatchThreadAction->setChecked(false);
02240   }
02241 }
02242 
02243 //-----------------------------------------------------------------------------
02244 void KMMainWidget::slotNextMessage()       { mHeaders->nextMessage(); }
02245 void KMMainWidget::slotNextUnreadMessage()
02246 {
02247   if ( !mHeaders->nextUnreadMessage() )
02248     if ( GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders )
02249       mFolderTree->nextUnreadFolder(true);
02250 }
02251 void KMMainWidget::slotNextImportantMessage() {
02252   //mHeaders->nextImportantMessage();
02253 }
02254 void KMMainWidget::slotPrevMessage()       { mHeaders->prevMessage(); }
02255 void KMMainWidget::slotPrevUnreadMessage()
02256 {
02257   if ( !mHeaders->prevUnreadMessage() )
02258     if ( GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders )
02259       mFolderTree->prevUnreadFolder();
02260 }
02261 void KMMainWidget::slotPrevImportantMessage() {
02262   //mHeaders->prevImportantMessage();
02263 }
02264 
02265 void KMMainWidget::slotDisplayCurrentMessage()
02266 {
02267   if ( mHeaders->currentMsg() )
02268     slotMsgActivated( mHeaders->currentMsg() );
02269 }
02270 
02271 //-----------------------------------------------------------------------------
02272 //called from headers. Message must not be deleted on close
02273 void KMMainWidget::slotMsgActivated(KMMessage *msg)
02274 {
02275   if ( !msg ) return;
02276   if ( msg->parent() && !msg->isComplete() ) {
02277     FolderJob *job = msg->parent()->createJob( msg );
02278     connect( job, SIGNAL( messageRetrieved( KMMessage* ) ),
02279              SLOT( slotMsgActivated( KMMessage* ) ) );
02280     job->start();
02281     return;
02282   }
02283 
02284   if (kmkernel->folderIsDraftOrOutbox( mFolder ) ) {
02285     slotEditMsg();
02286     return;
02287   }
02288   if ( kmkernel->folderIsTemplates( mFolder ) ) {
02289     slotUseTemplate();
02290     return;
02291   }
02292 
02293   assert( msg != 0 );
02294   KMReaderMainWin *win = new KMReaderMainWin( mFolderHtmlPref, mFolderHtmlLoadExtPref );
02295   KConfigGroup reader( KMKernel::config(), "Reader" );
02296   bool useFixedFont = mMsgView ? mMsgView->isFixedFont()
02297                                : reader.readBoolEntry( "useFixedFont", false );
02298   win->setUseFixedFont( useFixedFont );
02299   KMMessage *newMessage = new KMMessage(*msg);
02300   newMessage->setParent( msg->parent() );
02301   newMessage->setMsgSerNum( msg->getMsgSerNum() );
02302   newMessage->setReadyToShow( true );
02303   win->showMsg( overrideEncoding(), newMessage );
02304   win->show();
02305 }
02306 
02307 //-----------------------------------------------------------------------------
02308 void KMMainWidget::slotMarkAll()
02309 {
02310   mHeaders->selectAll( TRUE );
02311 }
02312 
02313 //-----------------------------------------------------------------------------
02314 void KMMainWidget::slotMsgPopup(KMMessage&, const KURL &aUrl, const QPoint& aPoint)
02315 {
02316   KPopupMenu * menu = new KPopupMenu;
02317   updateMessageMenu();
02318   mUrlCurrent = aUrl;
02319 
02320   bool urlMenuAdded = false;
02321 
02322   if (!aUrl.isEmpty())
02323   {
02324     if (aUrl.protocol() == "mailto")
02325     {
02326       // popup on a mailto URL
02327       mMsgView->mailToComposeAction()->plug( menu );
02328       mMsgView->mailToReplyAction()->plug( menu );
02329       mMsgView->mailToForwardAction()->plug( menu );
02330 
02331       menu->insertSeparator();
02332       mMsgView->addAddrBookAction()->plug( menu );
02333       mMsgView->openAddrBookAction()->plug( menu );
02334       mMsgView->copyURLAction()->plug( menu );
02335       mMsgView->startImChatAction()->plug( menu );
02336       // only enable if our KIMProxy is functional
02337       mMsgView->startImChatAction()->setEnabled( kmkernel->imProxy()->initialize() );
02338 
02339     } else {
02340       // popup on a not-mailto URL
02341       mMsgView->urlOpenAction()->plug( menu );
02342       mMsgView->addBookmarksAction()->plug( menu );
02343       mMsgView->urlSaveAsAction()->plug( menu );
02344       mMsgView->copyURLAction()->plug( menu );
02345     }
02346     if ( aUrl.protocol() == "im" )
02347     {
02348       // popup on an IM address
02349       // no need to check the KIMProxy is initialized, as these protocols will
02350       // only be present if it is.
02351       mMsgView->startImChatAction()->plug( menu );
02352     }
02353 
02354     urlMenuAdded=true;
02355     kdDebug( 0 ) << k_funcinfo << " URL is: " << aUrl << endl;
02356   }
02357 
02358 
02359   if(mMsgView && !mMsgView->copyText().isEmpty()) {
02360     if ( urlMenuAdded )
02361       menu->insertSeparator();
02362     mReplyActionMenu->plug(menu);
02363     menu->insertSeparator();
02364 
02365     mMsgView->copyAction()->plug( menu );
02366     mMsgView->selectAllAction()->plug( menu );
02367   } else  if ( !urlMenuAdded )
02368   {
02369     // popup somewhere else (i.e., not a URL) on the message
02370 
02371     if (!mHeaders->currentMsg()) // no messages
02372     {
02373       delete menu;
02374       return;
02375     }
02376 
02377     if ( mFolder->isDrafts() || mFolder->isOutbox() ) {
02378       mEditAction->plug(menu);
02379     } else if ( mFolder->isTemplates() ) {
02380       mUseAction->plug( menu );
02381       mEditAction->plug( menu );
02382     } else {
02383       if ( !mFolder->isSent() )
02384         mReplyActionMenu->plug( menu );
02385       mForwardActionMenu->plug( menu );
02386     }
02387     menu->insertSeparator();
02388 
02389     mCopyActionMenu->plug( menu );
02390     mMoveActionMenu->plug( menu );
02391 
02392     menu->insertSeparator();
02393 
02394     mStatusMenu->plug( menu );
02395     menu->insertSeparator();
02396 
02397     viewSourceAction()->plug(menu);
02398     if(mMsgView) {
02399       mMsgView->toggleFixFontAction()->plug(menu);
02400     }
02401     menu->insertSeparator();
02402     mPrintAction->plug( menu );
02403     mSaveAsAction->plug( menu );
02404     mSaveAttachmentsAction->plug( menu );
02405 
02406     menu->insertSeparator();
02407     if( mFolder->isTrash() )
02408       mDeleteAction->plug( menu );
02409     else
02410       mTrashAction->plug( menu );
02411   }
02412   KAcceleratorManager::manage(menu);
02413   menu->exec(aPoint, 0);
02414   delete menu;
02415 }
02416 
02417 //-----------------------------------------------------------------------------
02418 void KMMainWidget::getAccountMenu()
02419 {
02420   QStringList actList;
02421 
02422   mActMenu->clear();
02423   actList = kmkernel->acctMgr()->getAccounts();
02424   QStringList::Iterator it;
02425   int id = 0;
02426   for(it = actList.begin(); it != actList.end() ; ++it, id++)
02427     mActMenu->insertItem((*it).replace("&", "&&"), id);
02428 }
02429 
02430 //-----------------------------------------------------------------------------
02431 void KMMainWidget::getTransportMenu()
02432 {
02433   QStringList availTransports;
02434 
02435   mSendMenu->clear();
02436   availTransports = KMail::TransportManager::transportNames();
02437   QStringList::Iterator it;
02438   int id = 0;
02439   for(it = availTransports.begin(); it != availTransports.end() ; ++it, id++)
02440     mSendMenu->insertItem((*it).replace("&", "&&"), id);
02441 }
02442 
02443 //-----------------------------------------------------------------------------
02444 void KMMainWidget::updateCustomTemplateMenus()
02445 {
02446   if ( !mCustomTemplateActions.isEmpty() ) {
02447     QPtrList<KAction>::iterator ait = mCustomTemplateActions.begin();
02448     for ( ; ait != mCustomTemplateActions.end() ; ++ait ) {
02449       (*ait)->unplugAll();
02450       delete (*ait);
02451     }
02452     mCustomTemplateActions.clear();
02453   }
02454 
02455   delete mCustomReplyActionMenu;
02456   delete mCustomReplyAllActionMenu;
02457   delete mCustomForwardActionMenu;
02458 
02459   delete mCustomReplyMapper;
02460   delete mCustomReplyAllMapper;
02461   delete mCustomForwardMapper;
02462 
02463   mCustomForwardActionMenu =
02464     new KActionMenu( i18n("Forward With Custom Template"),
02465                      "mail_custom_forward",
02466                      actionCollection(), "custom_forward" );
02467   QSignalMapper *mCustomForwardMapper = new QSignalMapper( this );
02468   connect( mCustomForwardMapper, SIGNAL( mapped( int ) ),
02469            this, SLOT( slotCustomForwardMsg( int ) ) );
02470   mForwardActionMenu->insert( mCustomForwardActionMenu );
02471 
02472   mCustomReplyActionMenu =
02473     new KActionMenu( i18n("Reply With Custom Template"), "mail_custom_reply",
02474                      actionCollection(), "custom_reply" );
02475   QSignalMapper *mCustomReplyMapper = new QSignalMapper( this );
02476   connect( mCustomReplyMapper, SIGNAL( mapped( int ) ),
02477            this, SLOT( slotCustomReplyToMsg( int ) ) );
02478   mReplyActionMenu->insert( mCustomReplyActionMenu );
02479 
02480   mCustomReplyAllActionMenu =
02481     new KActionMenu( i18n("Reply to All With Custom Template"),
02482                      "mail_custom_reply_all",
02483                      actionCollection(), "custom_reply_all" );
02484   QSignalMapper *mCustomReplyAllMapper = new QSignalMapper( this );
02485   connect( mCustomReplyAllMapper, SIGNAL( mapped( int ) ),
02486            this, SLOT( slotCustomReplyAllToMsg( int ) ) );
02487   mReplyActionMenu->insert( mCustomReplyAllActionMenu );
02488 
02489   mCustomTemplates.clear();
02490 
02491   QStringList list = GlobalSettingsBase::self()->customTemplates();
02492   QStringList::iterator it = list.begin();
02493   int idx = 0;
02494   int replyc = 0;
02495   int replyallc = 0;
02496   int forwardc = 0;
02497   for ( ; it != list.end(); ++it ) {
02498     CTemplates t( *it );
02499     mCustomTemplates.append( *it );
02500 
02501     KAction *action;
02502     switch ( t.type() ) {
02503     case CustomTemplates::TReply:
02504       action = new KAction( (*it).replace( "&", "&&" ),
02505                             KShortcut( t.shortcut() ),
02506                             mCustomReplyMapper,
02507                             SLOT( map() ),
02508                             actionCollection(),
02509                             (*it).utf8() );
02510       mCustomReplyMapper->setMapping( action, idx );
02511       mCustomReplyActionMenu->insert( action, idx );
02512       mCustomTemplateActions.append( action );
02513       ++replyc;
02514       break;
02515     case CustomTemplates::TReplyAll:
02516       action = new KAction( (*it).replace( "&", "&&" ),
02517                             KShortcut( t.shortcut() ),
02518                             mCustomReplyAllMapper,
02519                             SLOT( map() ),
02520                             actionCollection(),
02521                             (*it).utf8() );
02522       mCustomReplyAllMapper->setMapping( action, idx );
02523       mCustomReplyAllActionMenu->insert( action, idx );
02524       mCustomTemplateActions.append( action );
02525       ++replyallc;
02526       break;
02527     case CustomTemplates::TForward:
02528       action = new KAction( (*it).replace( "&", "&&" ),
02529                             KShortcut( t.shortcut() ),
02530                             mCustomForwardMapper,
02531                             SLOT( map() ),
02532                             actionCollection(),
02533                             (*it).utf8() );
02534       mCustomForwardMapper->setMapping( action, idx );
02535       mCustomForwardActionMenu->insert( action, idx );
02536       mCustomTemplateActions.append( action );
02537       ++forwardc;
02538       break;
02539     case CustomTemplates::TUniversal:
02540       action = new KAction( (*it).replace( "&", "&&" ),
02541                             KShortcut::null(),
02542                             mCustomReplyMapper,
02543                             SLOT( map() ),
02544                             actionCollection(),
02545                             (*it).utf8() );
02546       mCustomReplyMapper->setMapping( action, idx );
02547       mCustomReplyActionMenu->insert( action, idx );
02548       mCustomTemplateActions.append( action );
02549       ++replyc;
02550       action = new KAction( (*it).replace( "&", "&&" ),
02551                             KShortcut::null(),
02552                             mCustomReplyAllMapper,
02553                             SLOT( map() ),
02554                             actionCollection(),
02555                             (*it).utf8() );
02556       mCustomReplyAllMapper->setMapping( action, idx );
02557       mCustomReplyAllActionMenu->insert( action, idx );
02558       mCustomTemplateActions.append( action );
02559       ++replyallc;
02560       action = new KAction( (*it).replace( "&", "&&" ),
02561                             KShortcut::null(),
02562                             mCustomForwardMapper,
02563                             SLOT( map() ),
02564                             actionCollection(),
02565                             (*it).utf8() );
02566       mCustomForwardMapper->setMapping( action, idx );
02567       mCustomForwardActionMenu->insert( action, idx );
02568       mCustomTemplateActions.append( action );
02569       ++forwardc;
02570       break;
02571     }
02572 
02573     ++idx;
02574   }
02575   if ( !replyc ) {
02576       mCustomReplyActionMenu->popupMenu()->insertItem( i18n( "(no custom templates)" ), 0 );
02577       mCustomReplyActionMenu->popupMenu()->setItemEnabled( 0, false );
02578       mCustomReplyActionMenu->setEnabled(false);
02579   }
02580   if ( !replyallc ) {
02581       mCustomReplyAllActionMenu->popupMenu()->insertItem( i18n( "(no custom templates)" ), 0 );
02582       mCustomReplyAllActionMenu->popupMenu()->setItemEnabled( 0, false );
02583       mCustomReplyAllActionMenu->setEnabled(false);
02584   }
02585   if ( !forwardc ) {
02586       mCustomForwardActionMenu->popupMenu()->insertItem( i18n( "(no custom templates)" ), 0 );
02587       mCustomForwardActionMenu->popupMenu()->setItemEnabled( 0, false );
02588       mCustomForwardActionMenu->setEnabled(false);
02589   }
02590 
02591 }
02592 
02593 
02594 //-----------------------------------------------------------------------------
02595 void KMMainWidget::setupActions()
02596 {
02597   //----- File Menu
02598   mSaveAsAction = new KAction( i18n("Save &As..."), "filesave",
02599     KStdAccel::shortcut(KStdAccel::Save),
02600     this, SLOT(slotSaveMsg()), actionCollection(), "file_save_as" );
02601 
02602   mOpenAction = KStdAction::open( this, SLOT( slotOpenMsg() ),
02603                                   actionCollection() );
02604 
02605   (void) new KAction( i18n("&Compact All Folders"), 0,
02606               this, SLOT(slotCompactAll()),
02607               actionCollection(), "compact_all_folders" );
02608 
02609   (void) new KAction( i18n("&Expire All Folders"), 0,
02610               this, SLOT(slotExpireAll()),
02611               actionCollection(), "expire_all_folders" );
02612 
02613   (void) new KAction( i18n("&Refresh Local IMAP Cache"), "refresh",
02614               this, SLOT(slotInvalidateIMAPFolders()),
02615               actionCollection(), "file_invalidate_imap_cache" );
02616 
02617   (void) new KAction( i18n("Empty All &Trash Folders"), 0,
02618               KMKernel::self(), SLOT(slotEmptyTrash()),
02619               actionCollection(), "empty_trash" );
02620 
02621   (void) new KAction( i18n("Check &Mail"), "mail_get", CTRL+Key_L,
02622               this, SLOT(slotCheckMail()),
02623               actionCollection(), "check_mail" );
02624 
02625   KActionMenu *actActionMenu = new
02626     KActionMenu( i18n("Check Mail &In"), "mail_get", actionCollection(),
02627                     "check_mail_in" );
02628   actActionMenu->setDelayed(true); //needed for checking "all accounts"
02629 
02630   connect(actActionMenu,SIGNAL(activated()),this,SLOT(slotCheckMail()));
02631 
02632   mActMenu = actActionMenu->popupMenu();
02633   connect(mActMenu,SIGNAL(activated(int)),this,SLOT(slotCheckOneAccount(int)));
02634   connect(mActMenu,SIGNAL(aboutToShow()),this,SLOT(getAccountMenu()));
02635 
02636   (void) new KAction( i18n("&Send Queued Messages"), "mail_send", 0, this,
02637              SLOT(slotSendQueued()), actionCollection(), "send_queued");
02638 
02639   (void) new KAction( i18n("Online Status (unknown)"), "online_status", 0, this,
02640                      SLOT(slotOnlineStatus()), actionCollection(), "online_status");
02641 
02642   KActionMenu *sendActionMenu = new
02643     KActionMenu( i18n("Send Queued Messages Via"), "mail_send_via", actionCollection(),
02644                                        "send_queued_via" );
02645   sendActionMenu->setDelayed(true);
02646 
02647   mSendMenu = sendActionMenu->popupMenu();
02648   connect(mSendMenu,SIGNAL(activated(int)), this, SLOT(slotSendQueuedVia(int)));
02649   connect(mSendMenu,SIGNAL(aboutToShow()),this,SLOT(getTransportMenu()));
02650 
02651   KAction *act;
02652   //----- Tools menu
02653   if (parent()->inherits("KMMainWin")) {
02654     act =  new KAction( i18n("&Address Book..."), "contents", 0, this,
02655             SLOT(slotAddrBook()), actionCollection(), "addressbook" );
02656     if (KStandardDirs::findExe("kaddressbook").isEmpty()) act->setEnabled(false);
02657   }
02658 
02659   act = new KAction( i18n("Certificate Manager..."), "pgp-keys", 0, this,
02660              SLOT(slotStartCertManager()), actionCollection(), "tools_start_certman");
02661   // disable action if no certman binary is around
02662   if (KStandardDirs::findExe("kleopatra").isEmpty()) act->setEnabled(false);
02663 
02664   act = new KAction( i18n("GnuPG Log Viewer..."), "pgp-keys", 0, this,
02665              SLOT(slotStartWatchGnuPG()), actionCollection(), "tools_start_kwatchgnupg");
02666   // disable action if no kwatchgnupg binary is around
02667   if (KStandardDirs::findExe("kwatchgnupg").isEmpty()) act->setEnabled(false);
02668 
02669   act = new KAction( i18n("&Import Messages..."), "fileopen", 0, this,
02670              SLOT(slotImport()), actionCollection(), "import" );
02671   if (KStandardDirs::findExe("kmailcvt").isEmpty()) act->setEnabled(false);
02672 
02673 #if !defined(NDEBUG)
02674   (void) new KAction( i18n("&Debug Sieve..."),
02675               "idea", 0, this, SLOT(slotDebugSieve()),
02676               actionCollection(), "tools_debug_sieve" );
02677 #endif
02678 
02679   // @TODO (marc/bo): Test
02680   (void) new KAction( i18n("Edit \"Out of Office\" Replies..."),
02681               "configure", 0, this, SLOT(slotEditVacation()),
02682               actionCollection(), "tools_edit_vacation" );
02683 
02684   (void) new KAction( i18n("Filter &Log Viewer..."), 0, this,
02685               SLOT(slotFilterLogViewer()), actionCollection(), "filter_log_viewer" );
02686 
02687   (void) new KAction( i18n("&Anti-Spam Wizard..."), 0, this,
02688               SLOT(slotAntiSpamWizard()), actionCollection(), "antiSpamWizard" );
02689   (void) new KAction( i18n("&Anti-Virus Wizard..."), 0, this,
02690               SLOT(slotAntiVirusWizard()), actionCollection(), "antiVirusWizard" );
02691 
02692   //----- Edit Menu
02693   mTrashAction = new KAction( KGuiItem( i18n("&Move to Trash"), "edittrash",
02694                                        i18n("Move message to trashcan") ),
02695                              Key_Delete, this, SLOT(slotTrashMsg()),
02696                              actionCollection(), "move_to_trash" );
02697 
02698   /* The delete action is nowhere in the gui, by default, so we need to make
02699    * sure it is plugged into the KAccel now, since that won't happen on
02700    * XMLGui construction or manual ->plug(). This is only a problem when run
02701    * as a part, though. */
02702   mDeleteAction = new KAction( i18n("&Delete"), "editdelete", SHIFT+Key_Delete, this,
02703                               SLOT(slotDeleteMsg()), actionCollection(), "delete" );
02704   mDeleteAction->plugAccel( actionCollection()->kaccel() );
02705 
02706   mTrashThreadAction = new KAction( KGuiItem( i18n("M&ove Thread to Trash"), "edittrash",
02707                                        i18n("Move thread to trashcan") ),
02708                              CTRL+Key_Delete, this, SLOT(slotTrashThread()),
02709                              actionCollection(), "move_thread_to_trash" );
02710 
02711   mDeleteThreadAction = new KAction( i18n("Delete T&hread"), "editdelete", CTRL+SHIFT+Key_Delete, this,
02712                               SLOT(slotDeleteThread()), actionCollection(), "delete_thread" );
02713 
02714 
02715   (void) new KAction( i18n("&Find Messages..."), "mail_find", Key_S, this,
02716               SLOT(slotSearch()), actionCollection(), "search_messages" );
02717 
02718   mFindInMessageAction = new KAction( i18n("&Find in Message..."), "find", KStdAccel::shortcut(KStdAccel::Find), this,
02719               SLOT(slotFind()), actionCollection(), "find_in_messages" );
02720 
02721   (void) new KAction( i18n("Select &All Messages"), KStdAccel::selectAll(), this,
02722               SLOT(slotMarkAll()), actionCollection(), "mark_all_messages" );
02723 
02724   //----- Folder Menu
02725   mNewFolderAction = new KAction( i18n("&New Folder..."), "folder_new", 0, mFolderTree,
02726               SLOT(addChildFolder()), actionCollection(), "new_folder" );
02727 
02728   mModifyFolderAction = new KAction( i18n("&Properties"), "configure", 0, this,
02729               SLOT(slotModifyFolder()), actionCollection(), "modify" );
02730 
02731   mFolderMailingListPropertiesAction = new KAction( i18n("&Mailing List Management..."),
02732       /*"folder_mailinglist_properties",*/ 0, this, SLOT( slotFolderMailingListProperties() ),
02733       actionCollection(), "folder_mailinglist_properties" );
02734 
02735   mFolderShortCutCommandAction = new KAction( i18n("&Assign Shortcut..."), "configure_shortcuts",
02736                       0, this, SLOT( slotFolderShortcutCommand() ), actionCollection(),
02737                       "folder_shortcut_command" );
02738 
02739 
02740   mMarkAllAsReadAction = new KAction( i18n("Mark All Messages as &Read"), "goto", 0, this,
02741               SLOT(slotMarkAllAsRead()), actionCollection(), "mark_all_as_read" );
02742 
02743   mExpireFolderAction = new KAction(i18n("&Expiration Settings"), 0, this, SLOT(slotExpireFolder()),
02744                    actionCollection(), "expire");
02745 
02746   mCompactFolderAction = new KAction( i18n("&Compact Folder"), 0, this,
02747               SLOT(slotCompactFolder()), actionCollection(), "compact" );
02748 
02749   mRefreshFolderAction = new KAction( i18n("Check Mail &in This Folder"), "reload",
02750                                       KStdAccel::shortcut( KStdAccel::Reload ), this,
02751                                       SLOT(slotRefreshFolder()),
02752                                       actionCollection(), "refresh_folder" );
02753   mTroubleshootFolderAction = 0; // set in initializeIMAPActions
02754 
02755   mEmptyFolderAction = new KAction( "foo" /*set in updateFolderMenu*/, "edittrash", 0, this,
02756               SLOT(slotEmptyFolder()), actionCollection(), "empty" );
02757 
02758   mRemoveFolderAction = new KAction( "foo" /*set in updateFolderMenu*/, "editdelete", 0, this,
02759               SLOT(slotRemoveFolder()), actionCollection(), "delete_folder" );
02760 
02761   mPreferHtmlAction = new KToggleAction( i18n("Prefer &HTML to Plain Text"), 0, this,
02762               SLOT(slotOverrideHtml()), actionCollection(), "prefer_html" );
02763 
02764   mPreferHtmlLoadExtAction = new KToggleAction( i18n("Load E&xternal References"), 0, this,
02765               SLOT(slotOverrideHtmlLoadExt()), actionCollection(), "prefer_html_external_refs" );
02766 
02767   mThreadMessagesAction = new KToggleAction( i18n("&Thread Messages"), 0, this,
02768               SLOT(slotOverrideThread()), actionCollection(), "thread_messages" );
02769 
02770   mThreadBySubjectAction = new KToggleAction( i18n("Thread Messages also by &Subject"), 0, this,
02771               SLOT(slotToggleSubjectThreading()), actionCollection(), "thread_messages_by_subject" );
02772 
02773   new KAction( i18n("Copy Folder"), "editcopy", SHIFT+CTRL+Key_C, folderTree(),
02774                SLOT(copyFolder()), actionCollection(), "copy_folder" );
02775   new KAction( i18n("Cut Folder"), "editcut", SHIFT+CTRL+Key_X, folderTree(),
02776                SLOT(cutFolder()), actionCollection(), "cut_folder" );
02777   new KAction( i18n("Paste Folder"), "editpaste", SHIFT+CTRL+Key_V, folderTree(),
02778                SLOT(pasteFolder()), actionCollection(), "paste_folder" );
02779 
02780   new KAction( i18n("Copy Messages"), "editcopy", ALT+CTRL+Key_C, headers(),
02781                SLOT(copyMessages()), actionCollection(), "copy_messages" );
02782   new KAction( i18n("Cut Messages"), "editcut", ALT+CTRL+Key_X, headers(),
02783                SLOT(cutMessages()), actionCollection(), "cut_messages" );
02784   new KAction( i18n("Paste Messages"), "editpaste", ALT+CTRL+Key_V, headers(),
02785                SLOT(pasteMessages()), actionCollection(), "paste_messages" );
02786 
02787   //----- Message Menu
02788   (void) new KAction( i18n("&New Message..."), "mail_new", KStdAccel::shortcut(KStdAccel::New), this,
02789               SLOT(slotCompose()), actionCollection(), "new_message" );
02790   mTemplateMenu =
02791     new KActionMenu( i18n("New Message From &Template"), "filenew",
02792                      actionCollection(), "new_from_template" );
02793   mTemplateMenu->setDelayed( true );
02794   connect( mTemplateMenu->popupMenu(), SIGNAL( aboutToShow() ), this,
02795            SLOT( slotShowNewFromTemplate() ) );
02796   connect( mTemplateMenu->popupMenu(), SIGNAL( activated(int) ), this,
02797            SLOT( slotNewFromTemplate(int) ) );
02798 
02799   (void) new KAction( i18n("New Message t&o Mailing-List..."), "mail_post_to",
02800                       CTRL+SHIFT+Key_N, this,
02801               SLOT(slotPostToML()), actionCollection(), "post_message" );
02802 
02803   mForwardActionMenu = new KActionMenu( i18n("Message->","&Forward"),
02804                     "mail_forward", actionCollection(),
02805                     "message_forward" );
02806   connect( mForwardActionMenu, SIGNAL(activated()), this,
02807        SLOT(slotForwardInlineMsg()) );
02808 
02809   mForwardAttachedAction = new KAction( i18n("Message->Forward->","As &Attachment..."),
02810                        "mail_forward", Key_F, this,
02811                     SLOT(slotForwardAttachedMsg()),
02812                                         actionCollection(),
02813                     "message_forward_as_attachment" );
02814   mForwardActionMenu->insert( forwardAttachedAction() );
02815   mForwardInlineAction = new KAction( i18n("&Inline..."), "mail_forward",
02816                                       SHIFT+Key_F, this,
02817                                       SLOT(slotForwardInlineMsg()),
02818                                       actionCollection(),
02819                                       "message_forward_inline" );
02820 
02821   mForwardActionMenu->insert( forwardInlineAction() );
02822   mForwardDigestAction = new KAction( i18n("Message->Forward->","As Di&gest..."),
02823                                       "mail_forward", 0, this,
02824                                       SLOT(slotForwardDigestMsg()),
02825                                       actionCollection(),
02826                                       "message_forward_as_digest" );
02827   mForwardActionMenu->insert( forwardDigestAction() );
02828   mRedirectAction = new KAction( i18n("Message->Forward->","&Redirect..."),
02829                                  "mail_forward", Key_E, this,
02830                                  SLOT(slotRedirectMsg()),
02831                  actionCollection(),
02832                                  "message_forward_redirect" );
02833   mForwardActionMenu->insert( redirectAction() );
02834 
02835   mSendAgainAction = new KAction( i18n("Send A&gain..."), 0, this,
02836               SLOT(slotResendMsg()), actionCollection(), "send_again" );
02837 
02838   mReplyActionMenu = new KActionMenu( i18n("Message->","&Reply"),
02839                                       "mail_reply", actionCollection(),
02840                                       "message_reply_menu" );
02841   connect( mReplyActionMenu, SIGNAL(activated()), this,
02842        SLOT(slotReplyToMsg()) );
02843 
02844   mReplyAction = new KAction( i18n("&Reply..."), "mail_reply", Key_R, this,
02845                   SLOT(slotReplyToMsg()), actionCollection(), "reply" );
02846   mReplyActionMenu->insert( mReplyAction );
02847 
02848   mReplyAuthorAction = new KAction( i18n("Reply to A&uthor..."), "mail_reply",
02849                                     SHIFT+Key_A, this,
02850                                     SLOT(slotReplyAuthorToMsg()),
02851                                     actionCollection(), "reply_author" );
02852   mReplyActionMenu->insert( mReplyAuthorAction );
02853 
02854   mReplyAllAction = new KAction( i18n("Reply to &All..."), "mail_replyall",
02855                  Key_A, this, SLOT(slotReplyAllToMsg()),
02856                  actionCollection(), "reply_all" );
02857   mReplyActionMenu->insert( mReplyAllAction );
02858 
02859   mReplyListAction = new KAction( i18n("Reply to Mailing-&List..."),
02860                   "mail_replylist", Key_L, this,
02861                   SLOT(slotReplyListToMsg()), actionCollection(),
02862                   "reply_list" );
02863   mReplyActionMenu->insert( mReplyListAction );
02864 
02865   mNoQuoteReplyAction = new KAction( i18n("Reply Without &Quote..."), SHIFT+Key_R,
02866     this, SLOT(slotNoQuoteReplyToMsg()), actionCollection(), "noquotereply" );
02867 
02868   //----- Create filter actions
02869   mFilterMenu = new KActionMenu( i18n("&Create Filter"), "filter", actionCollection(), "create_filter" );
02870   connect( mFilterMenu, SIGNAL(activated()), this,
02871        SLOT(slotFilter()) );
02872   mSubjectFilterAction = new KAction( i18n("Filter on &Subject..."), 0, this,
02873                       SLOT(slotSubjectFilter()),
02874                       actionCollection(), "subject_filter");
02875   mFilterMenu->insert( mSubjectFilterAction );
02876 
02877   mFromFilterAction = new KAction( i18n("Filter on &From..."), 0, this,
02878                    SLOT(slotFromFilter()),
02879                    actionCollection(), "from_filter");
02880   mFilterMenu->insert( mFromFilterAction );
02881 
02882   mToFilterAction = new KAction( i18n("Filter on &To..."), 0, this,
02883                  SLOT(slotToFilter()),
02884                  actionCollection(), "to_filter");
02885   mFilterMenu->insert( mToFilterAction );
02886 
02887   mListFilterAction = new KAction( i18n("Filter on Mailing-&List..."), 0, this,
02888                                    SLOT(slotMailingListFilter()), actionCollection(),
02889                                    "mlist_filter");
02890   mFilterMenu->insert( mListFilterAction );
02891 
02892   mPrintAction = KStdAction::print (this, SLOT(slotPrintMsg()), actionCollection());
02893 
02894   mEditAction = new KAction( i18n("&Edit Message"), "edit", Key_T, this,
02895                             SLOT(slotEditMsg()), actionCollection(), "edit" );
02896   mEditAction->plugAccel( actionCollection()->kaccel() );
02897   mUseAction = new KAction( i18n("New Message From &Template"), "filenew",
02898                             Key_N, this, SLOT( slotUseTemplate() ),
02899                             actionCollection(), "use_template" );
02900   mUseAction->plugAccel( actionCollection()->kaccel() );
02901 
02902   //----- "Mark Message" submenu
02903   mStatusMenu = new KActionMenu ( i18n( "Mar&k Message" ),
02904                                  actionCollection(), "set_status" );
02905 
02906   mStatusMenu->insert(new KAction(KGuiItem(i18n("Mark Message as &Read"), "kmmsgread",
02907                                           i18n("Mark selected messages as read")),
02908                                  0, this, SLOT(slotSetMsgStatusRead()),
02909                                  actionCollection(), "status_read"));
02910 
02911   mStatusMenu->insert(new KAction(KGuiItem(i18n("Mark Message as &New"), "kmmsgnew",
02912                                           i18n("Mark selected messages as new")),
02913                                  0, this, SLOT(slotSetMsgStatusNew()),
02914                                  actionCollection(), "status_new" ));
02915 
02916   mStatusMenu->insert(new KAction(KGuiItem(i18n("Mark Message as &Unread"), "kmmsgunseen",
02917                                           i18n("Mark selected messages as unread")),
02918                                  0, this, SLOT(slotSetMsgStatusUnread()),
02919                                  actionCollection(), "status_unread"));
02920 
02921   mStatusMenu->insert( new KActionSeparator( this ) );
02922 
02923   // -------- Toggle Actions
02924   mToggleFlagAction = new KToggleAction(i18n("Mark Message as &Important"), "mail_flag",
02925                                  0, this, SLOT(slotSetMsgStatusFlag()),
02926                                  actionCollection(), "status_flag");
02927   mToggleFlagAction->setCheckedState( i18n("Remove &Important Message Mark") );
02928   mStatusMenu->insert( mToggleFlagAction );
02929 
02930   mToggleTodoAction = new KToggleAction(i18n("Mark Message as &To-do"), "mail_todo",
02931                                  0, this, SLOT(slotSetMsgStatusTodo()),
02932                                  actionCollection(), "status_todo");
02933   mToggleTodoAction->setCheckedState( i18n("Remove &To-do Message Mark") );
02934   mStatusMenu->insert( mToggleTodoAction );
02935 
02936   //----- "Mark Thread" submenu
02937   mThreadStatusMenu = new KActionMenu ( i18n( "Mark &Thread" ),
02938                                        actionCollection(), "thread_status" );
02939 
02940   mMarkThreadAsReadAction = new KAction(KGuiItem(i18n("Mark Thread as &Read"), "kmmsgread",
02941                                                 i18n("Mark all messages in the selected thread as read")),
02942                                                 0, this, SLOT(slotSetThreadStatusRead()),
02943                                                 actionCollection(), "thread_read");
02944   mThreadStatusMenu->insert( mMarkThreadAsReadAction );
02945 
02946   mMarkThreadAsNewAction = new KAction(KGuiItem(i18n("Mark Thread as &New"), "kmmsgnew",
02947                                                i18n("Mark all messages in the selected thread as new")),
02948                                                0, this, SLOT(slotSetThreadStatusNew()),
02949                                                actionCollection(), "thread_new");
02950   mThreadStatusMenu->insert( mMarkThreadAsNewAction );
02951 
02952   mMarkThreadAsUnreadAction = new KAction(KGuiItem(i18n("Mark Thread as &Unread"), "kmmsgunseen",
02953                                                 i18n("Mark all messages in the selected thread as unread")),
02954                                                 0, this, SLOT(slotSetThreadStatusUnread()),
02955                                                 actionCollection(), "thread_unread");
02956   mThreadStatusMenu->insert( mMarkThreadAsUnreadAction );
02957 
02958   mThreadStatusMenu->insert( new KActionSeparator( this ) );
02959 
02960   //----- "Mark Thread" toggle actions
02961   mToggleThreadFlagAction = new KToggleAction(i18n("Mark Thread as &Important"), "mail_flag",
02962                                        0, this, SLOT(slotSetThreadStatusFlag()),
02963                                        actionCollection(), "thread_flag");
02964   mToggleThreadFlagAction->setCheckedState( i18n("Remove &Important Thread Mark") );
02965   mThreadStatusMenu->insert( mToggleThreadFlagAction );
02966 
02967   mToggleThreadTodoAction = new KToggleAction(i18n("Mark Thread as &To-do"), "mail_todo",
02968                                        0, this, SLOT(slotSetThreadStatusTodo()),
02969                                        actionCollection(), "thread_todo");
02970   mToggleThreadTodoAction->setCheckedState( i18n("Remove &To-do Thread Mark") );
02971   mThreadStatusMenu->insert( mToggleThreadTodoAction );
02972 
02973   //------- "Watch and ignore thread" actions
02974   mWatchThreadAction = new KToggleAction(i18n("&Watch Thread"), "kmmsgwatched",
02975                                        0, this, SLOT(slotSetThreadStatusWatched()),
02976                                        actionCollection(), "thread_watched");
02977 
02978   mIgnoreThreadAction = new KToggleAction(i18n("&Ignore Thread"), "mail_ignore",
02979                                        0, this, SLOT(slotSetThreadStatusIgnored()),
02980                                        actionCollection(), "thread_ignored");
02981 
02982   mThreadStatusMenu->insert( new KActionSeparator( this ) );
02983   mThreadStatusMenu->insert( mWatchThreadAction );
02984   mThreadStatusMenu->insert( mIgnoreThreadAction );
02985 
02986   mSaveAttachmentsAction = new KAction( i18n("Save A&ttachments..."), "attach",
02987                                 0, this, SLOT(slotSaveAttachments()),
02988                                 actionCollection(), "file_save_attachments" );
02989 
02990   mMoveActionMenu = new KActionMenu( i18n("&Move To" ),
02991                                     actionCollection(), "move_to" );
02992 
02993   mCopyActionMenu = new KActionMenu( i18n("&Copy To" ),
02994                                     actionCollection(), "copy_to" );
02995 
02996   mApplyAllFiltersAction = new KAction( i18n("Appl&y All Filters"), "filter",
02997                     CTRL+Key_J, this,
02998                     SLOT(slotApplyFilters()),
02999                     actionCollection(), "apply_filters" );
03000 
03001   mApplyFilterActionsMenu = new KActionMenu( i18n("A&pply Filter" ),
03002                         actionCollection(),
03003                         "apply_filter_actions" );
03004 
03005   //----- View Menu
03006   // Unread Submenu
03007   KActionMenu * unreadMenu =
03008     new KActionMenu( i18n("View->", "&Unread Count"),
03009              actionCollection(), "view_unread" );
03010   unreadMenu->setToolTip( i18n("Choose how to display the count of unread messages") );
03011 
03012   mUnreadColumnToggle = new KRadioAction( i18n("View->Unread Count", "View in &Separate Column"), 0, this,
03013                    SLOT(slotToggleUnread()),
03014                    actionCollection(), "view_unread_column" );
03015   mUnreadColumnToggle->setExclusiveGroup( "view_unread_group" );
03016   unreadMenu->insert( mUnreadColumnToggle );
03017 
03018   mUnreadTextToggle = new KRadioAction( i18n("View->Unread Count", "View After &Folder Name"), 0, this,
03019                    SLOT(slotToggleUnread()),
03020                    actionCollection(), "view_unread_text" );
03021   mUnreadTextToggle->setExclusiveGroup( "view_unread_group" );
03022   unreadMenu->insert( mUnreadTextToggle );
03023 
03024   // toggle for total column
03025   mTotalColumnToggle = new KToggleAction( i18n("View->", "&Total Column"), 0, this,
03026                    SLOT(slotToggleTotalColumn()),
03027                    actionCollection(), "view_columns_total" );
03028   mTotalColumnToggle->setToolTip( i18n("Toggle display of column showing the "
03029                                       "total number of messages in folders.") );
03030 
03031   (void)new KAction( KGuiItem( i18n("View->","&Expand Thread"), QString::null,
03032                    i18n("Expand the current thread") ),
03033              Key_Period, this,
03034              SLOT(slotExpandThread()),
03035              actionCollection(), "expand_thread" );
03036 
03037   (void)new KAction( KGuiItem( i18n("View->","&Collapse Thread"), QString::null,
03038                    i18n("Collapse the current thread") ),
03039              Key_Comma, this,
03040              SLOT(slotCollapseThread()),
03041              actionCollection(), "collapse_thread" );
03042 
03043   (void)new KAction( KGuiItem( i18n("View->","Ex&pand All Threads"), QString::null,
03044                    i18n("Expand all threads in the current folder") ),
03045              CTRL+Key_Period, this,
03046              SLOT(slotExpandAllThreads()),
03047              actionCollection(), "expand_all_threads" );
03048 
03049   (void)new KAction( KGuiItem( i18n("View->","C&ollapse All Threads"), QString::null,
03050                    i18n("Collapse all threads in the current folder") ),
03051              CTRL+Key_Comma, this,
03052              SLOT(slotCollapseAllThreads()),
03053              actionCollection(), "collapse_all_threads" );
03054 
03055   mViewSourceAction = new KAction( i18n("&View Source"), Key_V, this,
03056                                    SLOT(slotShowMsgSrc()), actionCollection(),
03057                                    "view_source" );
03058 
03059   KAction* dukeOfMonmoth = new KAction( i18n("&Display Message"), Key_Return, this,
03060                         SLOT( slotDisplayCurrentMessage() ), actionCollection(),
03061                         "display_message" );
03062   dukeOfMonmoth->plugAccel( actionCollection()->kaccel() );
03063 
03064   //----- Go Menu
03065   new KAction( KGuiItem( i18n("&Next Message"), QString::null,
03066                          i18n("Go to the next message") ),
03067                          "N;Right", this, SLOT(slotNextMessage()),
03068                          actionCollection(), "go_next_message" );
03069 
03070   new KAction( KGuiItem( i18n("Next &Unread Message"),
03071                          QApplication::reverseLayout() ? "previous" : "next",
03072                          i18n("Go to the next unread message") ),
03073                          Key_Plus, this, SLOT(slotNextUnreadMessage()),
03074                          actionCollection(), "go_next_unread_message" );
03075 
03076   /* ### needs better support from folders:
03077   new KAction( KGuiItem( i18n("Next &Important Message"), QString::null,
03078                          i18n("Go to the next important message") ),
03079                          0, this, SLOT(slotNextImportantMessage()),
03080                          actionCollection(), "go_next_important_message" );
03081   */
03082 
03083   new KAction( KGuiItem( i18n("&Previous Message"), QString::null,
03084                          i18n("Go to the previous message") ),
03085                          "P;Left", this, SLOT(slotPrevMessage()),
03086                          actionCollection(), "go_prev_message" );
03087 
03088   new KAction( KGuiItem( i18n("Previous Unread &Message"),
03089                          QApplication::reverseLayout() ? "next" : "previous",
03090                          i18n("Go to the previous unread message") ),
03091                          Key_Minus, this, SLOT(slotPrevUnreadMessage()),
03092                          actionCollection(), "go_prev_unread_message" );
03093 
03094   /* needs better support from folders:
03095   new KAction( KGuiItem( i18n("Previous I&mportant Message"), QString::null,
03096                          i18n("Go to the previous important message") ),
03097                          0, this, SLOT(slotPrevImportantMessage()),
03098                          actionCollection(), "go_prev_important_message" );
03099   */
03100 
03101   KAction *action =
03102     new KAction( KGuiItem( i18n("Next Unread &Folder"), QString::null,
03103                            i18n("Go to the next folder with unread messages") ),
03104                            ALT+Key_Plus, this, SLOT(slotNextUnreadFolder()),
03105                            actionCollection(), "go_next_unread_folder" );
03106   KShortcut shortcut = action->shortcut();
03107   shortcut.append( KKey( CTRL+Key_Plus ) );
03108   action->setShortcut( shortcut );
03109 
03110   action =
03111     new KAction( KGuiItem( i18n("Previous Unread F&older"), QString::null,
03112                            i18n("Go to the previous folder with unread messages") ),
03113                            ALT+Key_Minus, this, SLOT(slotPrevUnreadFolder()),
03114                            actionCollection(), "go_prev_unread_folder" );
03115   shortcut = action->shortcut();
03116   shortcut.append( KKey( CTRL+Key_Minus ) );
03117   action->setShortcut( shortcut );
03118 
03119   new KAction( KGuiItem( i18n("Go->","Next Unread &Text"), QString::null,
03120                          i18n("Go to the next unread text"),
03121                          i18n("Scroll down current message. "
03122                               "If at end of current message, "
03123                               "go to next unread message.") ),
03124                          Key_Space, this, SLOT(slotReadOn()),
03125                          actionCollection(), "go_next_unread_text" );
03126 
03127   //----- Settings Menu
03128   mToggleShowQuickSearchAction = new KToggleAction(i18n("Show Quick Search"), QString::null,
03129                                        0, this, SLOT(slotToggleShowQuickSearch()),
03130                                        actionCollection(), "show_quick_search");
03131   mToggleShowQuickSearchAction->setChecked( GlobalSettings::self()->quickSearchActive() );
03132   mToggleShowQuickSearchAction->setWhatsThis(
03133         i18n( GlobalSettings::self()->quickSearchActiveItem()->whatsThis().utf8() ) );
03134 
03135   (void) new KAction( i18n("Configure &Filters..."), 0, this,
03136               SLOT(slotFilter()), actionCollection(), "filter" );
03137   (void) new KAction( i18n("Configure &POP Filters..."), 0, this,
03138               SLOT(slotPopFilter()), actionCollection(), "popFilter" );
03139   (void) new KAction( i18n("Manage &Sieve Scripts..."), 0, this,
03140                       SLOT(slotManageSieveScripts()), actionCollection(), "sieveFilters" );
03141 
03142   (void) new KAction( KGuiItem( i18n("KMail &Introduction"), 0,
03143                 i18n("Display KMail's Welcome Page") ),
03144               0, this, SLOT(slotIntro()),
03145               actionCollection(), "help_kmail_welcomepage" );
03146 
03147   // ----- Standard Actions
03148 //  KStdAction::configureNotifications(this, SLOT(slotEditNotifications()), actionCollection());
03149   (void) new KAction( i18n("Configure &Notifications..."),
03150               "knotify", 0, this,
03151               SLOT(slotEditNotifications()), actionCollection(),
03152               "kmail_configure_notifications" );
03153 //  KStdAction::preferences(this, SLOT(slotSettings()), actionCollection());
03154   (void) new KAction( i18n("&Configure KMail..."),
03155               "configure", 0, kmkernel,
03156                       SLOT(slotShowConfigurationDialog()), actionCollection(),
03157                       "kmail_configure_kmail" );
03158 
03159   KStdAction::undo(this, SLOT(slotUndo()), actionCollection(), "kmail_undo");
03160 
03161   KStdAction::tipOfDay( this, SLOT( slotShowTip() ), actionCollection() );
03162 
03163   menutimer = new QTimer( this, "menutimer" );
03164   connect( menutimer, SIGNAL( timeout() ), SLOT( updateMessageActions() ) );
03165   connect( kmkernel->undoStack(),
03166            SIGNAL( undoStackChanged() ), this, SLOT( slotUpdateUndo() ));
03167 
03168   initializeIMAPActions( false ); // don't set state, config not read yet
03169   updateMessageActions();
03170   updateCustomTemplateMenus();
03171   updateFolderMenu();
03172 }
03173 
03174 //-----------------------------------------------------------------------------
03175 void KMMainWidget::slotEditNotifications()
03176 {
03177   if(kmkernel->xmlGuiInstance())
03178     KNotifyDialog::configure(this, 0, kmkernel->xmlGuiInstance()->aboutData());
03179   else
03180     KNotifyDialog::configure(this);
03181 }
03182 
03183 void KMMainWidget::slotEditKeys()
03184 {
03185   KKeyDialog::configure( actionCollection(),
03186              true /*allow one-letter shortcuts*/
03187              );
03188 }
03189 
03190 //-----------------------------------------------------------------------------
03191 void KMMainWidget::slotReadOn()
03192 {
03193     if ( !mMsgView )
03194         return;
03195 
03196     if ( !mMsgView->atBottom() ) {
03197         mMsgView->slotJumpDown();
03198         return;
03199     }
03200     slotNextUnreadMessage();
03201 }
03202 
03203 void KMMainWidget::slotNextUnreadFolder() {
03204   if ( !mFolderTree ) return;
03205   mFolderTree->nextUnreadFolder();
03206 }
03207 
03208 void KMMainWidget::slotPrevUnreadFolder() {
03209   if ( !mFolderTree ) return;
03210   mFolderTree->prevUnreadFolder();
03211 }
03212 
03213 void KMMainWidget::slotExpandThread()
03214 {
03215   mHeaders->slotExpandOrCollapseThread( true ); // expand
03216 }
03217 
03218 void KMMainWidget::slotCollapseThread()
03219 {
03220   mHeaders->slotExpandOrCollapseThread( false ); // collapse
03221 }
03222 
03223 void KMMainWidget::slotExpandAllThreads()
03224 {
03225   mHeaders->slotExpandOrCollapseAllThreads( true ); // expand
03226 }
03227 
03228 void KMMainWidget::slotCollapseAllThreads()
03229 {
03230   mHeaders->slotExpandOrCollapseAllThreads( false ); // collapse
03231 }
03232 
03233 //-----------------------------------------------------------------------------
03234 void KMMainWidget::slotShowMsgSrc()
03235 {
03236   if ( mMsgView )
03237     mMsgView->setUpdateAttachment( false );
03238   KMMessage *msg = mHeaders->currentMsg();
03239   if ( !msg )
03240     return;
03241   KMCommand *command = new KMShowMsgSrcCommand( this, msg,
03242                                                 mMsgView
03243                                                 ? mMsgView->isFixedFont()
03244                                                 : false );
03245   command->start();
03246 }
03247 
03248 
03249 //-----------------------------------------------------------------------------
03250 void KMMainWidget::moveSelectedToFolder( int menuId )
03251 {
03252   if (mMenuToFolder[menuId])
03253     mHeaders->moveMsgToFolder( mMenuToFolder[menuId] );
03254 }
03255 
03256 
03257 //-----------------------------------------------------------------------------
03258 void KMMainWidget::copySelectedToFolder(int menuId )
03259 {
03260   if (mMenuToFolder[menuId])
03261     mHeaders->copyMsgToFolder( mMenuToFolder[menuId] );
03262 }
03263 
03264 
03265 //-----------------------------------------------------------------------------
03266 void KMMainWidget::updateMessageMenu()
03267 {
03268   mMenuToFolder.clear();
03269   folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage, this,
03270       &mMenuToFolder, mMoveActionMenu->popupMenu() );
03271   folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage, this,
03272       &mMenuToFolder, mCopyActionMenu->popupMenu() );
03273   updateMessageActions();
03274 }
03275 
03276 void KMMainWidget::startUpdateMessageActionsTimer()
03277 {
03278     menutimer->stop();
03279     menutimer->start( 20, true );
03280 }
03281 
03282 void KMMainWidget::updateMessageActions()
03283 {
03284     int count = 0;
03285     QPtrList<QListViewItem> selectedItems;
03286 
03287     if ( mFolder ) {
03288       for (QListViewItem *item = mHeaders->firstChild(); item; item = item->itemBelow())
03289         if (item->isSelected() )
03290           selectedItems.append(item);
03291       if ( selectedItems.isEmpty() && mFolder->count() ) // there will always be one in mMsgView
03292         count = 1;
03293       else
03294         count = selectedItems.count();
03295     }
03296 
03297     updateListFilterAction();
03298 
03299     bool allSelectedInCommonThread = false;
03300     if ( mHeaders->isThreaded() && count > 1 ) {
03301       allSelectedInCommonThread = true;
03302       QListViewItem * curItemParent = mHeaders->currentItem();
03303       while ( curItemParent->parent() )
03304         curItemParent = curItemParent->parent();
03305       for ( QPtrListIterator<QListViewItem> it( selectedItems ) ;
03306             it.current() ; ++ it ) {
03307         QListViewItem * item = *it;
03308         while ( item->parent() )
03309           item = item->parent();
03310         if ( item != curItemParent ) {
03311           allSelectedInCommonThread = false;
03312           break;
03313         }
03314       }
03315     }
03316     else if ( mHeaders->isThreaded() && count == 1 ) {
03317       allSelectedInCommonThread = true;
03318     }
03319 
03320     QListViewItem *curItemParent = mHeaders->currentItem();
03321     bool parent_thread = 0;
03322     if ( curItemParent && curItemParent->firstChild() != 0 ) parent_thread = 1;
03323 
03324     bool mass_actions = count >= 1;
03325     bool thread_actions = mass_actions && allSelectedInCommonThread &&
03326                           mHeaders->isThreaded();
03327     mStatusMenu->setEnabled( mass_actions );
03328     mThreadStatusMenu->setEnabled( thread_actions );
03329     // these need to be handled individually, the user might have them
03330     // in the toolbar
03331     mWatchThreadAction->setEnabled( thread_actions );
03332     mIgnoreThreadAction->setEnabled( thread_actions );
03333     mMarkThreadAsNewAction->setEnabled( thread_actions );
03334     mMarkThreadAsReadAction->setEnabled( thread_actions );
03335     mMarkThreadAsUnreadAction->setEnabled( thread_actions );
03336     mToggleThreadTodoAction->setEnabled( thread_actions );
03337     mToggleThreadFlagAction->setEnabled( thread_actions );
03338     mTrashThreadAction->setEnabled( thread_actions && !mFolder->isReadOnly() );
03339     mDeleteThreadAction->setEnabled( thread_actions && !mFolder->isReadOnly() );
03340 
03341     if (mFolder && mHeaders && mHeaders->currentMsg()) {
03342       mToggleTodoAction->setChecked(mHeaders->currentMsg()->isTodo());
03343       mToggleFlagAction->setChecked(mHeaders->currentMsg()->isImportant());
03344       if (thread_actions) {
03345         mToggleThreadTodoAction->setChecked(mHeaders->currentMsg()->isTodo());
03346         mToggleThreadFlagAction->setChecked(mHeaders->currentMsg()->isImportant());
03347         mWatchThreadAction->setChecked( mHeaders->currentMsg()->isWatched());
03348         mIgnoreThreadAction->setChecked( mHeaders->currentMsg()->isIgnored());
03349       }
03350     }
03351 
03352     mMoveActionMenu->setEnabled( mass_actions && !mFolder->isReadOnly() );
03353     mCopyActionMenu->setEnabled( mass_actions );
03354     mTrashAction->setEnabled( mass_actions && !mFolder->isReadOnly() );
03355     mDeleteAction->setEnabled( mass_actions && !mFolder->isReadOnly() );
03356     mFindInMessageAction->setEnabled( mass_actions );
03357     mForwardInlineAction->setEnabled( mass_actions );
03358     mForwardAttachedAction->setEnabled( mass_actions );
03359     mForwardDigestAction->setEnabled( count > 1 || parent_thread );
03360 
03361     forwardMenu()->setEnabled( mass_actions );
03362 
03363     bool single_actions = count == 1;
03364     mEditAction->setEnabled( single_actions &&
03365                              ( kmkernel->folderIsDraftOrOutbox( mFolder ) ||
03366                                kmkernel->folderIsTemplates( mFolder ) ) );
03367     mUseAction->setEnabled( single_actions &&
03368                             kmkernel->folderIsTemplates( mFolder ) );
03369     replyMenu()->setEnabled( single_actions );
03370     filterMenu()->setEnabled( single_actions );
03371     replyAction()->setEnabled( single_actions );
03372     noQuoteReplyAction()->setEnabled( single_actions );
03373     replyAuthorAction()->setEnabled( single_actions );
03374     replyAllAction()->setEnabled( single_actions );
03375     replyListAction()->setEnabled( single_actions );
03376     redirectAction()->setEnabled( single_actions );
03377     printAction()->setEnabled( single_actions );
03378     viewSourceAction()->setEnabled( single_actions );
03379 
03380     mSendAgainAction->setEnabled( single_actions &&
03381              ( mHeaders->currentMsg() && mHeaders->currentMsg()->isSent() )
03382           || ( mFolder && mHeaders->currentMsg() &&
03383               ( kmkernel->folderIsDraftOrOutbox( mFolder )
03384              || kmkernel->folderIsSentMailFolder( mFolder ) ) ) );
03385     mSaveAsAction->setEnabled( mass_actions );
03386     bool mails = mFolder && mFolder->count();
03387     bool enable_goto_unread = mails
03388        || (GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders);
03389     actionCollection()->action( "go_next_message" )->setEnabled( mails );
03390     actionCollection()->action( "go_next_unread_message" )->setEnabled( enable_goto_unread );
03391     actionCollection()->action( "go_prev_message" )->setEnabled( mails );
03392     actionCollection()->action( "go_prev_unread_message" )->setEnabled( enable_goto_unread );
03393     actionCollection()->action( "send_queued" )->setEnabled( kmkernel->outboxFolder()->count() > 0 );
03394     actionCollection()->action( "send_queued_via" )->setEnabled( kmkernel->outboxFolder()->count() > 0 );
03395     slotUpdateOnlineStatus( static_cast<GlobalSettingsBase::EnumNetworkState::type>( GlobalSettings::self()->networkState() ) );
03396     if (action( "edit_undo" ))
03397       action( "edit_undo" )->setEnabled( mHeaders->canUndo() );
03398 
03399     if ( count == 1 ) {
03400       KMMessage *msg;
03401       int aIdx;
03402       if((aIdx = mHeaders->currentItemIndex()) <= -1)
03403         return;
03404       if(!(msg = mFolder->getMsg(aIdx)))
03405         return;
03406 
03407       if ((KMFolder*)mFolder == kmkernel->outboxFolder())
03408         mEditAction->setEnabled( !msg->transferInProgress() );
03409     }
03410 
03411     mApplyAllFiltersAction->setEnabled(count);
03412     mApplyFilterActionsMenu->setEnabled(count);
03413 }
03414 
03415 // This needs to be updated more often, so it is in its method.
03416 void KMMainWidget::updateMarkAsReadAction()
03417 {
03418   mMarkAllAsReadAction->setEnabled( mFolder && (mFolder->countUnread() > 0) );
03419 }
03420 
03421 //-----------------------------------------------------------------------------
03422 void KMMainWidget::updateFolderMenu()
03423 {
03424   bool folderWithContent = mFolder && !mFolder->noContent();
03425   bool multiFolder = folderTree()->selectedFolders().count() > 1;
03426   mModifyFolderAction->setEnabled( folderWithContent && !multiFolder );
03427   mFolderMailingListPropertiesAction->setEnabled( folderWithContent && !multiFolder );
03428   mCompactFolderAction->setEnabled( folderWithContent && !multiFolder );
03429 
03430   // This is the refresh-folder action in the menu. See kmfoldertree for the one in the RMB...
03431   bool imap = mFolder && mFolder->folderType() == KMFolderTypeImap;
03432   bool cachedImap = mFolder && mFolder->folderType() == KMFolderTypeCachedImap;
03433   // For dimap, check that the imap path is known before allowing "check mail in this folder".
03434   bool knownImapPath = cachedImap && !static_cast<KMFolderCachedImap*>( mFolder->storage() )->imapPath().isEmpty();
03435   mRefreshFolderAction->setEnabled( folderWithContent && ( imap
03436                                                            || ( cachedImap && knownImapPath ) ) && !multiFolder );
03437   if ( mTroubleshootFolderAction )
03438     mTroubleshootFolderAction->setEnabled( folderWithContent && ( cachedImap && knownImapPath ) && !multiFolder );
03439   mEmptyFolderAction->setEnabled( folderWithContent && ( mFolder->count() > 0 ) && !mFolder->isReadOnly() && !multiFolder );
03440   mEmptyFolderAction->setText( (mFolder && kmkernel->folderIsTrash(mFolder))
03441     ? i18n("E&mpty Trash") : i18n("&Move All Messages to Trash") );
03442   mRemoveFolderAction->setEnabled( mFolder && !mFolder->isSystemFolder() && !mFolder->isReadOnly() && !multiFolder);
03443   mRemoveFolderAction->setText( mFolder && mFolder->folderType() == KMFolderTypeSearch
03444         ? i18n("&Delete Search") : i18n("&Delete Folder") );
03445   mExpireFolderAction->setEnabled( mFolder && mFolder->isAutoExpire() && !multiFolder );
03446   updateMarkAsReadAction();
03447   // the visual ones only make sense if we are showing a message list
03448   mPreferHtmlAction->setEnabled( mHeaders->folder() ? true : false );
03449   mPreferHtmlLoadExtAction->setEnabled( mHeaders->folder() && (mHtmlPref ? !mFolderHtmlPref : mFolderHtmlPref) ? true : false );
03450   mThreadMessagesAction->setEnabled( mHeaders->folder() ? true : false );
03451 
03452   mPreferHtmlAction->setChecked( mHtmlPref ? !mFolderHtmlPref : mFolderHtmlPref );
03453   mPreferHtmlLoadExtAction->setChecked( mHtmlLoadExtPref ? !mFolderHtmlLoadExtPref : mFolderHtmlLoadExtPref );
03454   mThreadMessagesAction->setChecked(
03455       mThreadPref ? !mFolderThreadPref : mFolderThreadPref );
03456   mThreadBySubjectAction->setEnabled(
03457       mHeaders->folder() ? ( mThreadMessagesAction->isChecked()) : false );
03458   mThreadBySubjectAction->setChecked( mFolderThreadSubjPref );
03459 
03460   mNewFolderAction->setEnabled( !multiFolder );
03461   mRemoveDuplicatesAction->setEnabled( !multiFolder );
03462   mFolderShortCutCommandAction->setEnabled( !multiFolder );
03463 }
03464 
03465 
03466 #ifdef MALLOC_DEBUG
03467 static QString fmt(long n) {
03468   char buf[32];
03469 
03470   if(n > 1024*1024*1024)
03471     sprintf(buf, "%0.2f GB", ((double)n)/1024.0/1024.0/1024.0);
03472   else if(n > 1024*1024)
03473     sprintf(buf, "%0.2f MB", ((double)n)/1024.0/1024.0);
03474   else if(n > 1024)
03475     sprintf(buf, "%0.2f KB", ((double)n)/1024.0);
03476   else
03477     sprintf(buf, "%ld Byte", n);
03478   return QString(buf);
03479 }
03480 #endif
03481 
03482 void KMMainWidget::slotMemInfo() {
03483 #ifdef MALLOC_DEBUG
03484   struct mallinfo mi;
03485 
03486   mi = mallinfo();
03487   QString s = QString("\nMALLOC - Info\n\n"
03488               "Number of mmapped regions : %1\n"
03489               "Memory allocated in use   : %2\n"
03490               "Memory allocated, not used: %3\n"
03491               "Memory total allocated    : %4\n"
03492               "Max. freeable memory      : %5\n")
03493     .arg(mi.hblks).arg(fmt(mi.uordblks)).arg(fmt(mi.fordblks))
03494     .arg(fmt(mi.arena)).arg(fmt(mi.keepcost));
03495   KMessageBox::information(0, s, "Malloc information", s);
03496 #endif
03497 }
03498 
03499 
03500 //-----------------------------------------------------------------------------
03501 void KMMainWidget::slotIntro()
03502 {
03503   if ( !mMsgView ) return;
03504 
03505   mMsgView->clear( true );
03506   // hide widgets that are in the way:
03507   if ( mSearchAndHeaders && mHeaders && mLongFolderList )
03508     mSearchAndHeaders->hide();
03509 
03510 
03511   mMsgView->displayAboutPage();
03512 
03513   closeFolder();
03514   mFolder = 0;
03515 }
03516 
03517 void KMMainWidget::slotShowStartupFolder()
03518 {
03519   if ( mFolderTree ) {
03520     mFolderTree->reload();
03521     mFolderTree->readConfig();
03522     // get rid of old-folders
03523     mFolderTree->cleanupConfigFile();
03524   }
03525 
03526   connect( kmkernel->filterMgr(), SIGNAL( filterListUpdated() ),
03527        this, SLOT( initializeFilterActions() ));
03528 
03529   // plug shortcut filter actions now
03530   initializeFilterActions();
03531 
03532   // plug folder shortcut actions
03533   initializeFolderShortcutActions();
03534 
03535   QString newFeaturesMD5 = KMReaderWin::newFeaturesMD5();
03536   if ( kmkernel->firstStart() ||
03537        GlobalSettings::self()->previousNewFeaturesMD5() != newFeaturesMD5 ) {
03538     GlobalSettings::self()->setPreviousNewFeaturesMD5( newFeaturesMD5 );
03539     slotIntro();
03540     return;
03541   }
03542 
03543   KMFolder* startup = 0;
03544   if ( !mStartupFolder.isEmpty() ) {
03545     // find the startup-folder
03546     startup = kmkernel->findFolderById( mStartupFolder );
03547   }
03548   if ( !startup )
03549     startup = kmkernel->inboxFolder();
03550 
03551   if ( mFolderTree ) {
03552     mFolderTree->showFolder( startup );
03553   }
03554 }
03555 
03556 void KMMainWidget::slotShowTip()
03557 {
03558   KTipDialog::showTip( this, QString::null, true );
03559 }
03560 
03561 //-----------------------------------------------------------------------------
03562 void KMMainWidget::slotChangeCaption(QListViewItem * i)
03563 {
03564   if ( !i ) return;
03565   // set the caption to the current full path
03566   QStringList names;
03567   for ( QListViewItem * item = i ; item ; item = item->parent() )
03568     names.prepend( item->text(0) );
03569   emit captionChangeRequest( names.join( "/" ) );
03570 }
03571 
03572 //-----------------------------------------------------------------------------
03573 void KMMainWidget::removeDuplicates()
03574 {
03575   if (!mFolder)
03576     return;
03577   KMFolder *oFolder = mFolder;
03578   mHeaders->setFolder(0);
03579   QMap< QString, QValueList<int> > idMD5s;
03580   QValueList<int> redundantIds;
03581   QValueList<int>::Iterator kt;
03582   mFolder->open("removedups");
03583   for (int i = mFolder->count() - 1; i >= 0; --i) {
03584     QString id = (*mFolder)[i]->msgIdMD5();
03585     if ( !id.isEmpty() ) {
03586       QString subjMD5 = (*mFolder)[i]->strippedSubjectMD5();
03587       int other = -1;
03588       if ( idMD5s.contains(id) )
03589         other = idMD5s[id].first();
03590       else
03591         idMD5s[id].append( i );
03592       if ( other != -1 ) {
03593         QString otherSubjMD5 = (*mFolder)[other]->strippedSubjectMD5();
03594         if (otherSubjMD5 == subjMD5)
03595           idMD5s[id].append( i );
03596       }
03597     }
03598   }
03599   QMap< QString, QValueList<int> >::Iterator it;
03600   for ( it = idMD5s.begin(); it != idMD5s.end() ; ++it ) {
03601     QValueList<int>::Iterator jt;
03602     bool finished = false;
03603     for ( jt = (*it).begin(); jt != (*it).end() && !finished; ++jt )
03604       if (!((*mFolder)[*jt]->isUnread())) {
03605         (*it).remove( jt );
03606         (*it).prepend( *jt );
03607         finished = true;
03608       }
03609     for ( jt = (*it).begin(), ++jt; jt != (*it).end(); ++jt )
03610       redundantIds.append( *jt );
03611   }
03612   qHeapSort( redundantIds );
03613   kt = redundantIds.end();
03614   int numDuplicates = 0;
03615   if (kt != redundantIds.begin()) do {
03616     mFolder->removeMsg( *(--kt) );
03617     ++numDuplicates;
03618   }
03619   while (kt != redundantIds.begin());
03620 
03621   mFolder->close("removedups");
03622   mHeaders->setFolder(oFolder);
03623   QString msg;
03624   if ( numDuplicates )
03625     msg = i18n("Removed %n duplicate message.",
03626                "Removed %n duplicate messages.", numDuplicates );
03627     else
03628       msg = i18n("No duplicate messages found.");
03629   BroadcastStatus::instance()->setStatusMsg( msg );
03630 }
03631 
03632 
03633 //-----------------------------------------------------------------------------
03634 void KMMainWidget::slotUpdateUndo()
03635 {
03636     if (actionCollection()->action( "edit_undo" ))
03637         actionCollection()->action( "edit_undo" )->setEnabled( mHeaders->canUndo() );
03638 }
03639 
03640 
03641 //-----------------------------------------------------------------------------
03642 void KMMainWidget::clearFilterActions()
03643 {
03644   if ( !mFilterTBarActions.isEmpty() ) {
03645     if ( mGUIClient->factory() )
03646       mGUIClient->unplugActionList( "toolbar_filter_actions" );
03647     mFilterTBarActions.clear();
03648   }
03649   mApplyFilterActionsMenu->popupMenu()->clear();
03650   if ( !mFilterMenuActions.isEmpty() ) {
03651     if ( mGUIClient->factory() )
03652       mGUIClient->unplugActionList( "menu_filter_actions" );
03653     mFilterMenuActions.clear();
03654   }
03655   mFilterCommands.clear();
03656 }
03657 
03658 //-----------------------------------------------------------------------------
03659 void KMMainWidget::initializeFolderShortcutActions()
03660 {
03661 
03662   // If we are loaded as a part, this will be set to fals, since the part
03663   // does xml loading. Temporarily set to true, in that case, so the
03664   // accels are added to the collection as expected.
03665   bool old = actionCollection()->isAutoConnectShortcuts();
03666 
03667   actionCollection()->setAutoConnectShortcuts( true );
03668   QValueList< QGuardedPtr< KMFolder > > folders = kmkernel->allFolders();
03669   QValueList< QGuardedPtr< KMFolder > >::Iterator it = folders.begin();
03670   while ( it != folders.end() ) {
03671     KMFolder *folder = (*it);
03672     ++it;
03673     slotShortcutChanged( folder ); // load the initial accel
03674   }
03675   actionCollection()->setAutoConnectShortcuts( old );
03676 }
03677 
03678 
03679 //-----------------------------------------------------------------------------
03680 void KMMainWidget::initializeFilterActions()
03681 {
03682   QString filterName, normalizedName;
03683   KMMetaFilterActionCommand *filterCommand;
03684   KAction *filterAction = 0;
03685 
03686   clearFilterActions();
03687   mApplyAllFiltersAction->plug(mApplyFilterActionsMenu->popupMenu());
03688   bool addedSeparator = false;
03689   QValueListConstIterator<KMFilter*> it = kmkernel->filterMgr()->filters().constBegin();
03690   for ( ;it != kmkernel->filterMgr()->filters().constEnd(); ++it ) {
03691     if (!(*it)->isEmpty() && (*it)->configureShortcut()) {
03692       filterName = QString("Filter %1").arg((*it)->name());
03693       normalizedName = filterName.replace(" ", "_");
03694       if (action(normalizedName.utf8()))
03695         continue;
03696       filterCommand = new KMMetaFilterActionCommand(*it, mHeaders, this);
03697       mFilterCommands.append(filterCommand);
03698       QString as = i18n("Filter %1").arg((*it)->name());
03699       QString icon = (*it)->icon();
03700       if ( icon.isEmpty() )
03701         icon = "gear";
03702       filterAction = new KAction(as, icon, (*it)->shortcut(), filterCommand,
03703                                  SLOT(start()), actionCollection(),
03704                                  normalizedName.local8Bit());
03705       if(!addedSeparator) {
03706         mApplyFilterActionsMenu->popupMenu()->insertSeparator();
03707         addedSeparator = !addedSeparator;
03708     mFilterMenuActions.append( new KActionSeparator());
03709       }
03710       filterAction->plug( mApplyFilterActionsMenu->popupMenu() );
03711       mFilterMenuActions.append(filterAction);
03712       if ( (*it)->configureToolbar() )
03713         mFilterTBarActions.append(filterAction);
03714     }
03715   }
03716   if ( !mFilterMenuActions.isEmpty() && mGUIClient->factory() )
03717     mGUIClient->plugActionList( "menu_filter_actions", mFilterMenuActions );
03718   if ( !mFilterTBarActions.isEmpty() && mGUIClient->factory() ) {
03719     mFilterTBarActions.prepend( mToolbarActionSeparator );
03720     mGUIClient->plugActionList( "toolbar_filter_actions", mFilterTBarActions );
03721   }
03722 }
03723 
03724 void KMMainWidget::slotFolderRemoved( KMFolder *folder )
03725 {
03726   mFolderShortcutCommands.remove( folder->idString() );
03727 }
03728 
03729 //-----------------------------------------------------------------------------
03730 void KMMainWidget::initializeIMAPActions( bool setState /* false the first time, true later on */ )
03731 {
03732   bool hasImapAccount = false;
03733   for( KMAccount *a = kmkernel->acctMgr()->first(); a;
03734        a = kmkernel->acctMgr()->next() ) {
03735     if ( a->type() == "cachedimap" ) {
03736       hasImapAccount = true;
03737       break;
03738     }
03739   }
03740   if ( hasImapAccount == ( mTroubleshootFolderAction != 0 ) )
03741     return; // nothing to do
03742 
03743   KXMLGUIFactory* factory = mGUIClient->factory();
03744   if ( factory )
03745     factory->removeClient( mGUIClient );
03746 
03747   if ( !mTroubleshootFolderAction ) {
03748     mTroubleshootFolderAction = new KAction( i18n("&Troubleshoot IMAP Cache..."), "wizard", 0,
03749      this, SLOT(slotTroubleshootFolder()), actionCollection(), "troubleshoot_folder" );
03750     if ( setState )
03751       updateFolderMenu(); // set initial state of the action
03752   } else {
03753     delete mTroubleshootFolderAction ;
03754     mTroubleshootFolderAction = 0;
03755   }
03756 
03757   if ( factory )
03758     factory->addClient( mGUIClient );
03759 }
03760 
03761 bool KMMainWidget::shortcutIsValid( const KShortcut &sc ) const
03762 {
03763   KActionPtrList actions = actionCollection()->actions();
03764   KActionPtrList::Iterator it( actions.begin() );
03765   for ( ; it != actions.end(); it++ ) {
03766     if ( (*it)->shortcut() == sc ) return false;
03767   }
03768   return true;
03769 }
03770 
03771 void KMMainWidget::slotShortcutChanged( KMFolder *folder )
03772 {
03773   // remove the old one, autodelete
03774   mFolderShortcutCommands.remove( folder->idString() );
03775   if ( folder->shortcut().isNull() )
03776     return;
03777 
03778   FolderShortcutCommand *c = new FolderShortcutCommand( this, folder );
03779   mFolderShortcutCommands.insert( folder->idString(), c );
03780 
03781   QString actionlabel = QString( "FolderShortcut %1").arg( folder->prettyURL() );
03782   QString actionname = QString( "FolderShortcut %1").arg( folder->idString() );
03783   QString normalizedName = actionname.replace(" ", "_");
03784   KAction* action =
03785     new KAction(actionlabel, folder->shortcut(), c, SLOT(start()),
03786                 actionCollection(), normalizedName.local8Bit());
03787   action->setIcon( folder->unreadIconPath() );
03788   c->setAction( action ); // will be deleted along with the command
03789 }
03790 
03791 //-----------------------------------------------------------------------------
03792 QString KMMainWidget::findCurrentImapPath()
03793 {
03794   QString startPath;
03795   if (!mFolder) return startPath;
03796   if (mFolder->folderType() == KMFolderTypeImap)
03797   {
03798     startPath = static_cast<KMFolderImap*>(mFolder->storage())->imapPath();
03799   } else if (mFolder->folderType() == KMFolderTypeCachedImap)
03800   {
03801     startPath = static_cast<KMFolderCachedImap*>(mFolder->storage())->imapPath();
03802   }
03803   return startPath;
03804 }
03805 
03806 //-----------------------------------------------------------------------------
03807 ImapAccountBase* KMMainWidget::findCurrentImapAccountBase()
03808 {
03809   ImapAccountBase* account = 0;
03810   if (!mFolder) return account;
03811   if (mFolder->folderType() == KMFolderTypeImap)
03812   {
03813     account = static_cast<KMFolderImap*>(mFolder->storage())->account();
03814   } else if (mFolder->folderType() == KMFolderTypeCachedImap)
03815   {
03816     account = static_cast<KMFolderCachedImap*>(mFolder->storage())->account();
03817   }
03818   return account;
03819 }
03820 
03821 //-----------------------------------------------------------------------------
03822 void KMMainWidget::slotSubscriptionDialog()
03823 {
03824   if ( !kmkernel->askToGoOnline() )
03825     return;
03826   ImapAccountBase* account = findCurrentImapAccountBase();
03827   if ( !account ) return;
03828   const QString startPath = findCurrentImapPath();
03829 
03830   // KSubscription sets "DestruciveClose"
03831   SubscriptionDialog * dialog =
03832       new SubscriptionDialog(this, i18n("Subscription"), account, startPath);
03833   if ( dialog->exec() ) {
03834     // start a new listing
03835     if (mFolder->folderType() == KMFolderTypeImap)
03836       static_cast<KMFolderImap*>(mFolder->storage())->account()->listDirectory();
03837   }
03838 }
03839 
03840 //-----------------------------------------------------------------------------
03841 void KMMainWidget::slotLocalSubscriptionDialog()
03842 {
03843   ImapAccountBase* account = findCurrentImapAccountBase();
03844   if ( !account ) return;
03845 
03846   const QString startPath = findCurrentImapPath();
03847   // KSubscription sets "DestruciveClose"
03848   LocalSubscriptionDialog *dialog =
03849       new LocalSubscriptionDialog(this, i18n("Local Subscription"), account, startPath);
03850   if ( dialog->exec() ) {
03851     // start a new listing
03852     if (mFolder->folderType() == KMFolderTypeImap)
03853       static_cast<KMFolderImap*>(mFolder->storage())->account()->listDirectory();
03854   }
03855 }
03856 
03857 //-----------------------------------------------------------------------------
03858 void KMMainWidget::slotFolderTreeColumnsChanged()
03859 {
03860   mTotalColumnToggle->setChecked( mFolderTree->isTotalActive() );
03861   mUnreadColumnToggle->setChecked( mFolderTree->isUnreadActive() );
03862 }
03863 
03864 void KMMainWidget::toggleSystemTray()
03865 {
03866   if ( !mSystemTray && GlobalSettings::self()->systemTrayEnabled() ) {
03867     mSystemTray = new KMSystemTray();
03868   }
03869   else if ( mSystemTray && !GlobalSettings::self()->systemTrayEnabled() ) {
03870     // Get rid of system tray on user's request
03871     kdDebug(5006) << "deleting systray" << endl;
03872     delete mSystemTray;
03873     mSystemTray = 0;
03874   }
03875 
03876   // Set mode of systemtray. If mode has changed, tray will handle this.
03877   if ( mSystemTray )
03878     mSystemTray->setMode( GlobalSettings::self()->systemTrayPolicy() );
03879 }
03880 
03881 //-----------------------------------------------------------------------------
03882 void KMMainWidget::slotAntiSpamWizard()
03883 {
03884   AntiSpamWizard wiz( AntiSpamWizard::AntiSpam, this, folderTree() );
03885   wiz.exec();
03886 }
03887 
03888 //-----------------------------------------------------------------------------
03889 void KMMainWidget::slotAntiVirusWizard()
03890 {
03891   AntiSpamWizard wiz( AntiSpamWizard::AntiVirus, this, folderTree() );
03892   wiz.exec();
03893 }
03894 
03895 //-----------------------------------------------------------------------------
03896 void KMMainWidget::slotFilterLogViewer()
03897 {
03898   FilterLogDialog * dlg = new FilterLogDialog( 0 );
03899   dlg->show();
03900 }
03901 
03902 //-----------------------------------------------------------------------------
03903 void KMMainWidget::updateFileMenu()
03904 {
03905   QStringList actList = kmkernel->acctMgr()->getAccounts();
03906 
03907   actionCollection()->action("check_mail")->setEnabled( actList.size() > 0 );
03908   actionCollection()->action("check_mail_in")->setEnabled( actList.size() > 0 );
03909 }
03910 
03911 
03912 //-----------------------------------------------------------------------------
03913 void KMMainWidget::setAccelsEnabled( bool enabled )
03914 {
03915   actionCollection()->kaccel()->setEnabled( enabled );
03916 }
03917 
03918 
03919 //-----------------------------------------------------------------------------
03920 KMSystemTray *KMMainWidget::systray() const
03921 {
03922   return mSystemTray;
03923 }
03924 
03925 //-----------------------------------------------------------------------------
03926 QString KMMainWidget::overrideEncoding() const
03927 {
03928   if ( mMsgView )
03929     return mMsgView->overrideEncoding();
03930   else
03931     return GlobalSettings::self()->overrideCharacterEncoding();
03932 }
KDE Home | KDE Accessibility Home | Description of Access Keys