• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kmail

  • sources
  • kde-4.14
  • kdepim
  • kmail
kmmainwidget.cpp
Go to the documentation of this file.
1 /* -*- mode: C++; c-file-style: "gnu" -*-
2  This file is part of KMail, the KDE mail client.
3  Copyright (c) 2002 Don Sanders <sanders@kde.org>
4  Copyright (c) 2009-2015 Montel Laurent <montel@kde.org>
5 
6  Based on the work of Stefan Taferner <taferner@kde.org>
7 
8  KMail is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License, version 2, as
10  published by the Free Software Foundation.
11 
12  KMail is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License along
18  with this program; if not, write to the Free Software Foundation, Inc.,
19  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
22 // KMail includes
23 #include "kmreadermainwin.h"
24 #include "editor/composer.h"
25 #include "searchdialog/searchwindow.h"
26 #include "antispam-virus/antispamwizard.h"
27 #include "widgets/vacationscriptindicatorwidget.h"
28 #include "undostack.h"
29 #include "kmcommands.h"
30 #include "kmmainwin.h"
31 #include "kmsystemtray.h"
32 #include "customtemplatesmenu.h"
33 #include "folderselectiondialog.h"
34 #include "foldertreewidget.h"
35 #include "util.h"
36 #include "util/mailutil.h"
37 #include "kernel/mailkernel.h"
38 #include "dialog/archivefolderdialog.h"
39 #include "settings/globalsettings.h"
40 #include "foldertreeview.h"
41 #include "tag/tagactionmanager.h"
42 #include "foldershortcutactionmanager.h"
43 #include "widgets/collectionpane.h"
44 #include "manageshowcollectionproperties.h"
45 #include "widgets/kactionmenutransport.h"
46 #include "widgets/kactionmenuaccount.h"
47 #include "search/searchrule/searchrulestatus.h"
48 #if !defined(NDEBUG)
49 #include <ksieveui/debug/sievedebugdialog.h>
50 using KSieveUi::SieveDebugDialog;
51 #endif
52 
53 #include "collectionpage/collectionmaintenancepage.h"
54 #include "collectionpage/collectionquotapage.h"
55 #include "collectionpage/collectiontemplatespage.h"
56 #include "collectionpage/collectionshortcutpage.h"
57 #include "collectionpage/collectionviewpage.h"
58 #include "collectionpage/collectionmailinglistpage.h"
59 #include "tag/tagselectdialog.h"
60 #include "job/createnewcontactjob.h"
61 #include "folderarchive/folderarchiveutil.h"
62 #include "folderarchive/folderarchivemanager.h"
63 
64 #include "pimcommon/acl/collectionaclpage.h"
65 #include "mailcommon/collectionpage/collectiongeneralpage.h"
66 #include "mailcommon/collectionpage/collectionexpirypage.h"
67 #include "mailcommon/collectionpage/attributes/expirecollectionattribute.h"
68 #include "mailcommon/filter/filtermanager.h"
69 #include "mailcommon/filter/mailfilter.h"
70 #include "mailcommon/widgets/favoritecollectionwidget.h"
71 #include "mailcommon/folder/foldertreewidget.h"
72 #include "mailcommon/folder/foldertreeview.h"
73 #include "mailcommon/mailcommonsettings_base.h"
74 #include "kmmainwidget.h"
75 
76 // Other PIM includes
77 #include "kdepim-version.h"
78 
79 #include "messageviewer/utils/autoqpointer.h"
80 #include "messageviewer/settings/globalsettings.h"
81 #include "messageviewer/viewer/viewer.h"
82 #include "messageviewer/viewer/attachmentstrategy.h"
83 #include "messageviewer/header/headerstrategy.h"
84 #include "messageviewer/header/headerstyle.h"
85 #ifndef QT_NO_CURSOR
86 #include "messageviewer/utils/kcursorsaver.h"
87 #endif
88 
89 #include "messagecomposer/sender/messagesender.h"
90 #include "messagecomposer/helper/messagehelper.h"
91 
92 #include "templateparser/templateparser.h"
93 
94 #include "messagecore/settings/globalsettings.h"
95 #include "messagecore/misc/mailinglist.h"
96 #include "messagecore/helpers/messagehelpers.h"
97 
98 #include "dialog/kmknotify.h"
99 #include "widgets/displaymessageformatactionmenu.h"
100 
101 #include "ksieveui/vacation/vacationmanager.h"
102 #include "kmlaunchexternalcomponent.h"
103 
104 // LIBKDEPIM includes
105 #include "progresswidget/progressmanager.h"
106 #include "misc/broadcaststatus.h"
107 
108 // KDEPIMLIBS includes
109 #include <Akonadi/AgentManager>
110 #include <Akonadi/AttributeFactory>
111 #include <akonadi/itemfetchjob.h>
112 #include <akonadi/collectionfetchscope.h>
113 #include <akonadi/contact/contactsearchjob.h>
114 #include <akonadi/collectionpropertiesdialog.h>
115 #include <akonadi/entitydisplayattribute.h>
116 #include <akonadi/entitylistview.h>
117 #include <akonadi/etmviewstatesaver.h>
118 #include <akonadi/agentinstance.h>
119 #include <akonadi/agenttype.h>
120 #include <akonadi/changerecorder.h>
121 #include <akonadi/session.h>
122 #include <akonadi/entitytreemodel.h>
123 #include <akonadi/favoritecollectionsmodel.h>
124 #include <akonadi/itemfetchscope.h>
125 #include <akonadi/itemmodifyjob.h>
126 #include <akonadi/control.h>
127 #include <akonadi/collectiondialog.h>
128 #include <akonadi/collectionstatistics.h>
129 #include <Akonadi/EntityMimeTypeFilterModel>
130 #include <akonadi/kmime/messageflags.h>
131 #include <akonadi/kmime/removeduplicatesjob.h>
132 #include <akonadi/dbusconnectionpool.h>
133 #include <Akonadi/CachePolicy>
134 
135 #include <kpimidentities/identity.h>
136 #include <kpimidentities/identitymanager.h>
137 #include <kpimutils/email.h>
138 #include <mailtransport/transportmanager.h>
139 #include <mailtransport/transport.h>
140 #include <kmime/kmime_mdn.h>
141 #include <kmime/kmime_header_parsing.h>
142 #include <kmime/kmime_message.h>
143 #include <ksieveui/managesievescriptsdialog.h>
144 #include <ksieveui/util/util.h>
145 
146 // KDELIBS includes
147 #include <kaboutdata.h>
148 #include <kicon.h>
149 #include <kwindowsystem.h>
150 #include <kmessagebox.h>
151 #include <kactionmenu.h>
152 #include <kmenu.h>
153 #include <kacceleratormanager.h>
154 #include <kglobal.h>
155 #include <kglobalsettings.h>
156 #include <kstandardshortcut.h>
157 #include <kcharsets.h>
158 #include <kdebug.h>
159 #include <kfiledialog.h>
160 #include <ktip.h>
161 #include <kstandarddirs.h>
162 #include <kstandardaction.h>
163 #include <ktoggleaction.h>
164 #include <knotification.h>
165 #include <knotifyconfigwidget.h>
166 #include <kstringhandler.h>
167 #include <kconfiggroup.h>
168 #include <ktoolinvocation.h>
169 #include <kxmlguifactory.h>
170 #include <kxmlguiclient.h>
171 #include <kstatusbar.h>
172 #include <kaction.h>
173 #include <ktreewidgetsearchline.h>
174 #include <KRecentFilesAction>
175 
176 // Qt includes
177 #include <QByteArray>
178 #include <QHeaderView>
179 #include <QList>
180 #include <QSplitter>
181 #include <QVBoxLayout>
182 #include <QShortcut>
183 #include <QProcess>
184 #include <QDBusMessage>
185 #include <QDBusConnection>
186 #include <QTextDocument>
187 #include <QMenu>
188 
189 #include <akonadi/standardactionmanager.h>
190 #include <job/manageserversidesubscriptionjob.h>
191 #include <job/removeduplicatemailjob.h>
192 #include <job/removecollectionjob.h>
193 
194 
195 using namespace KMime;
196 using namespace Akonadi;
197 using namespace MailCommon;
198 using KPIM::ProgressManager;
199 using KPIM::BroadcastStatus;
200 using KMail::SearchWindow;
201 using KMail::AntiSpamWizard;
202 using KMime::Types::AddrSpecList;
203 using MessageViewer::AttachmentStrategy;
204 
205 K_GLOBAL_STATIC( KMMainWidget::PtrList, theMainWidgetList )
206 
207 //-----------------------------------------------------------------------------
208 KMMainWidget::KMMainWidget( QWidget *parent, KXMLGUIClient *aGUIClient,
209  KActionCollection *actionCollection, KSharedConfig::Ptr config ) :
210  QWidget( parent ),
211  mMoveMsgToFolderAction(0),
212  mCollectionProperties( 0 ),
213  mFavoriteCollectionsView( 0 ),
214  mMsgView( 0 ),
215  mSplitter1( 0 ),
216  mSplitter2( 0 ),
217  mFolderViewSplitter( 0 ),
218  mArchiveFolderAction( 0 ),
219  mShowBusySplashTimer( 0 ),
220  mMsgActions( 0 ),
221  mCurrentFolder( 0 ),
222  mVacationIndicatorActive( false ),
223  mGoToFirstUnreadMessageInSelectedFolder( false ),
224  mDisplayMessageFormatMenu( 0 ),
225  mFolderDisplayFormatPreference(MessageViewer::Viewer::UseGlobalSetting),
226  mSearchMessages( 0 ),
227  mManageShowCollectionProperties(new ManageShowCollectionProperties(this, this)),
228  mShowIntroductionAction( 0 )
229 {
230  mLaunchExternalComponent = new KMLaunchExternalComponent(this, this);
231  // must be the first line of the constructor:
232  mStartupDone = false;
233  mWasEverShown = false;
234  mReaderWindowActive = true;
235  mReaderWindowBelow = true;
236  mFolderHtmlLoadExtPreference = false;
237  mDestructed = false;
238  mActionCollection = actionCollection;
239  mTopLayout = new QVBoxLayout( this );
240  mTopLayout->setMargin( 0 );
241  mConfig = config;
242  mGUIClient = aGUIClient;
243  mFolderTreeWidget = 0;
244  mPreferHtmlLoadExtAction = 0;
245  Akonadi::Control::widgetNeedsAkonadi( this );
246  mFavoritesModel = 0;
247  mVacationManager = new KSieveUi::VacationManager(this);
248 
249  mToolbarActionSeparator = new QAction( this );
250  mToolbarActionSeparator->setSeparator( true );
251 
252  theMainWidgetList->append( this );
253 
254  readPreConfig();
255  createWidgets();
256  setupActions();
257 
258 
259  readConfig();
260 
261  if ( !kmkernel->isOffline() ) { //kmail is set to online mode, make sure the agents are also online
262  kmkernel->setAccountStatus(true);
263  }
264 
265 
266  QTimer::singleShot( 0, this, SLOT(slotShowStartupFolder()));
267 
268  connect( kmkernel, SIGNAL(startCheckMail()),
269  this, SLOT(slotStartCheckMail()) );
270 
271  connect( kmkernel, SIGNAL(endCheckMail()),
272  this, SLOT(slotEndCheckMail()) );
273 
274  connect( kmkernel, SIGNAL(configChanged()),
275  this, SLOT(slotConfigChanged()) );
276 
277  connect( kmkernel, SIGNAL(onlineStatusChanged(GlobalSettings::EnumNetworkState::type)),
278  this, SLOT(slotUpdateOnlineStatus(GlobalSettings::EnumNetworkState::type)) );
279 
280  connect( mTagActionManager, SIGNAL(tagActionTriggered(Akonadi::Tag)),
281  this, SLOT(slotUpdateMessageTagList(Akonadi::Tag)) );
282 
283  connect( mTagActionManager, SIGNAL(tagMoreActionClicked()),
284  this, SLOT(slotSelectMoreMessageTagList()) );
285 
286  kmkernel->toggleSystemTray();
287 
288  { // make sure the pages are registered only once, since there can be multiple instances of KMMainWidget
289  static bool pagesRegistered = false;
290 
291  if ( !pagesRegistered ) {
292  Akonadi::CollectionPropertiesDialog::registerPage( new PimCommon::CollectionAclPageFactory );
293  Akonadi::CollectionPropertiesDialog::registerPage( new MailCommon::CollectionGeneralPageFactory );
294  Akonadi::CollectionPropertiesDialog::registerPage( new CollectionMaintenancePageFactory );
295  Akonadi::CollectionPropertiesDialog::registerPage( new CollectionQuotaPageFactory );
296  Akonadi::CollectionPropertiesDialog::registerPage( new CollectionTemplatesPageFactory );
297  Akonadi::CollectionPropertiesDialog::registerPage( new MailCommon::CollectionExpiryPageFactory );
298  Akonadi::CollectionPropertiesDialog::registerPage( new CollectionViewPageFactory );
299  Akonadi::CollectionPropertiesDialog::registerPage( new CollectionMailingListPageFactory );
300  Akonadi::CollectionPropertiesDialog::registerPage( new CollectionShortcutPageFactory );
301 
302  pagesRegistered = true;
303  }
304  }
305 
306  KMainWindow *mainWin = dynamic_cast<KMainWindow*>(window());
307  KStatusBar *sb = mainWin ? mainWin->statusBar() : 0;
308  mVacationScriptIndicator = new KMail::VacationScriptIndicatorWidget( sb );
309  mVacationScriptIndicator->hide();
310  connect( mVacationScriptIndicator, SIGNAL(clicked(QString)), SLOT(slotEditVacation(QString)) );
311  if ( KSieveUi::Util::checkOutOfOfficeOnStartup() )
312  QTimer::singleShot( 0, this, SLOT(slotCheckVacation()) );
313 
314  connect( mFolderTreeWidget->folderTreeView()->model(), SIGNAL(modelReset()),
315  this, SLOT(restoreCollectionFolderViewConfig()) );
316  restoreCollectionFolderViewConfig();
317 
318  if ( kmkernel->firstStart() ) {
319  if (MailCommon::Util::foundMailer()) {
320  if (KMessageBox::questionYesNo(this,i18n("Another mailer was found on system. Do you want to import data from it?")) == KMessageBox::Yes) {
321  const QString path = KStandardDirs::findExe( QLatin1String("importwizard" ) );
322  if ( !QProcess::startDetached( path ) ) {
323  KMessageBox::error( this, i18n( "Could not start the import wizard. "
324  "Please check your installation." ),
325  i18n( "Unable to start import wizard" ) );
326  }
327  } else {
328  mLaunchExternalComponent->slotAccountWizard();
329  }
330  } else {
331  mLaunchExternalComponent->slotAccountWizard();
332  }
333  }
334  // must be the last line of the constructor:
335  mStartupDone = true;
336 
337 
338  mCheckMailTimer.setInterval( 3 * 1000 );
339  mCheckMailTimer.setSingleShot( true );
340  connect( &mCheckMailTimer, SIGNAL(timeout()), SLOT(slotUpdateActionsAfterMailChecking()) );
341 
342 }
343 
344 void KMMainWidget::restoreCollectionFolderViewConfig()
345 {
346  ETMViewStateSaver *saver = new ETMViewStateSaver;
347  saver->setView( mFolderTreeWidget->folderTreeView() );
348  const KConfigGroup cfg( KMKernel::self()->config(), "CollectionFolderView" );
349  mFolderTreeWidget->restoreHeaderState( cfg.readEntry( "HeaderState", QByteArray() ) );
350  saver->restoreState( cfg );
351  //Restore startup folder
352 
353  Akonadi::Collection::Id id = -1;
354  if (mCurrentFolder && mCurrentFolder->collection().isValid() ) {
355  id = mCurrentFolder->collection().id();
356  }
357 
358  if (id == -1) {
359  if (GlobalSettings::self()->startSpecificFolderAtStartup()) {
360  Akonadi::Collection::Id startupFolder = GlobalSettings::self()->startupFolder();
361  if ( startupFolder > 0 )
362  saver->restoreCurrentItem( QString::fromLatin1("c%1").arg(startupFolder) );
363  }
364  } else {
365  saver->restoreCurrentItem( QString::fromLatin1("c%1").arg(id) );
366  }
367 }
368 
369 
370 //-----------------------------------------------------------------------------
371 //The kernel may have already been deleted when this method is called,
372 //perform all cleanup that requires the kernel in destruct()
373 KMMainWidget::~KMMainWidget()
374 {
375  theMainWidgetList->removeAll( this );
376  qDeleteAll( mFilterCommands );
377  destruct();
378 }
379 
380 
381 //-----------------------------------------------------------------------------
382 //This method performs all cleanup that requires the kernel to exist.
383 void KMMainWidget::destruct()
384 {
385  if ( mDestructed )
386  return;
387  if ( mSearchWin )
388  mSearchWin->close();
389  writeConfig(false); /* don't force kmkernel sync when close BUG: 289287 */
390  writeFolderConfig();
391  deleteWidgets();
392  mCurrentFolder.clear();
393  delete mMoveOrCopyToDialog;
394  delete mSelectFromAllFoldersDialog;
395 
396  disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), this, 0);
397  disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)), this, 0);
398  disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), this, 0);
399  disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)), this, 0);
400  disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), this, 0);
401 
402  mDestructed = true;
403 }
404 
405 
406 void KMMainWidget::slotStartCheckMail()
407 {
408  if ( mCheckMailTimer.isActive() )
409  mCheckMailTimer.stop();
410 }
411 
412 void KMMainWidget::slotEndCheckMail()
413 {
414  if ( !mCheckMailTimer.isActive() )
415  mCheckMailTimer.start();
416 }
417 
418 void KMMainWidget::slotUpdateActionsAfterMailChecking()
419 {
420  const bool sendOnAll =
421  GlobalSettings::self()->sendOnCheck() == GlobalSettings::EnumSendOnCheck::SendOnAllChecks;
422  const bool sendOnManual =
423  GlobalSettings::self()->sendOnCheck() == GlobalSettings::EnumSendOnCheck::SendOnManualChecks;
424  if ( !kmkernel->isOffline() && ( sendOnAll || sendOnManual ) ) {
425  slotSendQueued();
426  }
427  // update folder menus in case some mail got filtered to trash/current folder
428  // and we can enable "empty trash/move all to trash" action etc.
429  updateFolderMenu();
430 }
431 
432 void KMMainWidget::slotCollectionFetched( int collectionId )
433 {
434  // Called when a collection is fetched for the first time by the ETM.
435  // This is the right time to update the caption (which still says "Loading...")
436  // and to update the actions that depend on the number of mails in the folder.
437  if ( mCurrentFolder && collectionId == mCurrentFolder->collection().id() ) {
438  mCurrentFolder->setCollection( MailCommon::Util::updatedCollection( mCurrentFolder->collection() ) );
439  updateMessageActions();
440  updateFolderMenu();
441  }
442  // We call this for any collection, it could be one of our parents...
443  if ( mCurrentFolder ) {
444  emit captionChangeRequest( MailCommon::Util::fullCollectionPath( mCurrentFolder->collection() ) );
445  }
446 }
447 
448 void KMMainWidget::slotFolderChanged( const Akonadi::Collection& collection )
449 {
450  folderSelected( collection );
451  if (collection.cachePolicy().syncOnDemand())
452  AgentManager::self()->synchronizeCollection( collection, false );
453  mMsgActions->setCurrentMessage( Akonadi::Item() );
454  emit captionChangeRequest( MailCommon::Util::fullCollectionPath( collection ) );
455 }
456 
457 void KMMainWidget::folderSelected( const Akonadi::Collection & col )
458 {
459  // This is connected to the MainFolderView signal triggering when a folder is selected
460 
461  if ( mGoToFirstUnreadMessageInSelectedFolder )
462  {
463  // the default action has been overridden from outside
464  mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered;
465  } else {
466  // use the default action
467  switch ( GlobalSettings::self()->actionEnterFolder() )
468  {
469  case GlobalSettings::EnumActionEnterFolder::SelectFirstUnread:
470  mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered;
471  break;
472  case GlobalSettings::EnumActionEnterFolder::SelectLastSelected:
473  mPreSelectionMode = MessageList::Core::PreSelectLastSelected;
474  break;
475  case GlobalSettings::EnumActionEnterFolder::SelectNewest:
476  mPreSelectionMode = MessageList::Core::PreSelectNewestCentered;
477  break;
478  case GlobalSettings::EnumActionEnterFolder::SelectOldest:
479  mPreSelectionMode = MessageList::Core::PreSelectOldestCentered;
480  break;
481  default:
482  mPreSelectionMode = MessageList::Core::PreSelectNone;
483  break;
484  }
485  }
486 
487  mGoToFirstUnreadMessageInSelectedFolder = false;
488 #ifndef QT_NO_CURSOR
489  MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() );
490 #endif
491 
492  if (mMsgView)
493  mMsgView->clear(true);
494  const bool newFolder = mCurrentFolder && ( mCurrentFolder->collection() != col );
495 
496  // Delete any pending timer, if needed it will be recreated below
497  delete mShowBusySplashTimer;
498  mShowBusySplashTimer = 0;
499  if ( newFolder )
500  {
501  // We're changing folder: write configuration for the old one
502  writeFolderConfig();
503  }
504 
505  mCurrentFolder = FolderCollection::forCollection( col );
506 
507  readFolderConfig();
508  if (mMsgView)
509  {
510  mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
511  mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
512  }
513 
514  if ( !mCurrentFolder->isValid() && ( mMessagePane->count() < 2 ) )
515  slotIntro();
516 
517  updateMessageActions();
518  updateFolderMenu();
519 
520  // The message pane uses the selection model of the folder view to load the correct aggregation model and theme
521  // settings. At this point the selection model hasn't been updated yet to the user's new choice, so it would load
522  // the old folder settings instead.
523  QTimer::singleShot( 0, this, SLOT(slotShowSelectedFolderInPane()) );
524 }
525 
526 void KMMainWidget::slotShowSelectedFolderInPane()
527 {
528  if ( mCurrentFolder && mCurrentFolder->collection().isValid() ) {
529  mMessagePane->setCurrentFolder( mCurrentFolder->collection(), false , mPreSelectionMode );
530  }
531 }
532 
533 void KMMainWidget::clearViewer()
534 {
535  if (mMsgView) {
536  mMsgView->clear( true );
537  mMsgView->displayAboutPage();
538  }
539 }
540 
541 //-----------------------------------------------------------------------------
542 void KMMainWidget::readPreConfig()
543 {
544  mLongFolderList = GlobalSettings::self()->folderList() == GlobalSettings::EnumFolderList::longlist;
545  mReaderWindowActive = GlobalSettings::self()->readerWindowMode() != GlobalSettings::EnumReaderWindowMode::hide;
546  mReaderWindowBelow = GlobalSettings::self()->readerWindowMode() == GlobalSettings::EnumReaderWindowMode::below;
547 
548  mHtmlGlobalSetting = MessageViewer::GlobalSettings::self()->htmlMail();
549  mHtmlLoadExtGlobalSetting = MessageViewer::GlobalSettings::self()->htmlLoadExternal();
550 
551  mEnableFavoriteFolderView = ( MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() != MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode );
552  mEnableFolderQuickSearch = GlobalSettings::self()->enableFolderQuickSearch();
553  readFolderConfig();
554  updateHtmlMenuEntry();
555  if (mMsgView) {
556  mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
557  mMsgView->update( true );
558  }
559 }
560 
561 
562 //-----------------------------------------------------------------------------
563 void KMMainWidget::readFolderConfig()
564 {
565  if ( !mCurrentFolder || !mCurrentFolder->isValid() )
566  return;
567  KSharedConfig::Ptr config = KMKernel::self()->config();
568  KConfigGroup group( config, MailCommon::FolderCollection::configGroupName( mCurrentFolder->collection() ) );
569  if (group.hasKey( "htmlMailOverride")) {
570  const bool useHtml = group.readEntry( "htmlMailOverride", false );
571  mFolderDisplayFormatPreference = useHtml ? MessageViewer::Viewer::Html : MessageViewer::Viewer::Text;
572  group.deleteEntry("htmlMailOverride");
573  group.sync();
574  } else {
575  mFolderDisplayFormatPreference = static_cast<MessageViewer::Viewer::DisplayFormatMessage>(group.readEntry( "displayFormatOverride", static_cast<int>(MessageViewer::Viewer::UseGlobalSetting)));
576  }
577  mFolderHtmlLoadExtPreference =
578  group.readEntry( "htmlLoadExternalOverride", false );
579 }
580 
581 
582 //-----------------------------------------------------------------------------
583 void KMMainWidget::writeFolderConfig()
584 {
585  if ( mCurrentFolder && mCurrentFolder->isValid() ) {
586  KSharedConfig::Ptr config = KMKernel::self()->config();
587  KConfigGroup group( config, MailCommon::FolderCollection::configGroupName( mCurrentFolder->collection() ) );
588  group.writeEntry( "htmlLoadExternalOverride", mFolderHtmlLoadExtPreference );
589  if (mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting)
590  group.deleteEntry("displayFormatOverride");
591  else
592  group.writeEntry( "displayFormatOverride", static_cast<int>(mFolderDisplayFormatPreference) );
593  }
594 }
595 
596 //-----------------------------------------------------------------------------
597 void KMMainWidget::layoutSplitters()
598 {
599  // This function can only be called when the old splitters are already deleted
600  Q_ASSERT( !mSplitter1 );
601  Q_ASSERT( !mSplitter2 );
602 
603  // For some reason, this is necessary here so that the copy action still
604  // works after changing the folder layout.
605  if ( mMsgView )
606  disconnect( mMsgView->copyAction(), SIGNAL(triggered(bool)),
607  mMsgView, SLOT(slotCopySelectedText()) );
608 
609  // If long folder list is enabled, the splitters are:
610  // Splitter 1: FolderView vs (HeaderAndSearch vs MessageViewer)
611  // Splitter 2: HeaderAndSearch vs MessageViewer
612  //
613  // If long folder list is disabled, the splitters are:
614  // Splitter 1: (FolderView vs HeaderAndSearch) vs MessageViewer
615  // Splitter 2: FolderView vs HeaderAndSearch
616 
617  // The folder view is both the folder tree and the favorite folder view, if
618  // enabled
619 
620  const bool opaqueResize = KGlobalSettings::opaqueResize();
621  const bool readerWindowAtSide = !mReaderWindowBelow && mReaderWindowActive;
622  const bool readerWindowBelow = mReaderWindowBelow && mReaderWindowActive;
623 
624  mSplitter1 = new QSplitter( this );
625  mSplitter2 = new QSplitter( mSplitter1 );
626 
627  QWidget * folderTreeWidget = mSearchAndTree;
628  if ( mFavoriteCollectionsView ) {
629  mFolderViewSplitter = new QSplitter( Qt::Vertical );
630  mFolderViewSplitter->setOpaqueResize( opaqueResize );
631  //mFolderViewSplitter->setChildrenCollapsible( false );
632  mFolderViewSplitter->addWidget( mFavoriteCollectionsView );
633  mFavoriteCollectionsView->setParent( mFolderViewSplitter );
634  mFolderViewSplitter->addWidget( mSearchAndTree );
635  folderTreeWidget = mFolderViewSplitter;
636  }
637 
638  if ( mLongFolderList ) {
639 
640  // add folder tree
641  mSplitter1->setOrientation( Qt::Horizontal );
642  mSplitter1->addWidget( folderTreeWidget );
643 
644  // and the rest to the right
645  mSplitter1->addWidget( mSplitter2 );
646 
647  // add the message list to the right or below
648  if ( readerWindowAtSide ) {
649  mSplitter2->setOrientation( Qt::Horizontal );
650  } else {
651  mSplitter2->setOrientation( Qt::Vertical );
652  }
653  mSplitter2->addWidget( mMessagePane );
654 
655  // add the preview window, if there is one
656  if ( mMsgView ) {
657  mSplitter2->addWidget( mMsgView );
658  }
659 
660  } else { // short folder list
661  if ( mReaderWindowBelow ) {
662  mSplitter1->setOrientation( Qt::Vertical );
663  mSplitter2->setOrientation( Qt::Horizontal );
664  } else { // at side or none
665  mSplitter1->setOrientation( Qt::Horizontal );
666  mSplitter2->setOrientation( Qt::Vertical );
667  }
668 
669  mSplitter1->addWidget( mSplitter2 );
670 
671  // add folder tree
672  mSplitter2->addWidget( folderTreeWidget );
673  // add message list to splitter 2
674  mSplitter2->addWidget( mMessagePane );
675 
676  // add the preview window, if there is one
677  if ( mMsgView )
678  mSplitter1->addWidget( mMsgView );
679  }
680 
681  //
682  // Set splitter properties
683  //
684  mSplitter1->setObjectName( QLatin1String("splitter1") );
685  mSplitter1->setOpaqueResize( opaqueResize );
686  //mSplitter1->setChildrenCollapsible( false );
687  mSplitter2->setObjectName( QLatin1String("splitter2") );
688  mSplitter2->setOpaqueResize( opaqueResize );
689  //mSplitter2->setChildrenCollapsible( false );
690 
691  //
692  // Set the stretch factors
693  //
694  mSplitter1->setStretchFactor( 0, 0 );
695  mSplitter2->setStretchFactor( 0, 0 );
696  mSplitter1->setStretchFactor( 1, 1 );
697  mSplitter2->setStretchFactor( 1, 1 );
698 
699  if ( mFavoriteCollectionsView ) {
700  mFolderViewSplitter->setStretchFactor( 0, 0 );
701  mFolderViewSplitter->setStretchFactor( 1, 1 );
702  }
703 
704  // Because the reader windows's width increases a tiny bit after each
705  // restart in short folder list mode with message window at side, disable
706  // the stretching as a workaround here
707  if ( readerWindowAtSide && !mLongFolderList ) {
708  mSplitter1->setStretchFactor( 0, 1 );
709  mSplitter1->setStretchFactor( 1, 0 );
710  }
711 
712  //
713  // Set the sizes of the splitters to the values stored in the config
714  //
715  QList<int> splitter1Sizes;
716  QList<int> splitter2Sizes;
717 
718  const int folderViewWidth = GlobalSettings::self()->folderViewWidth();
719  int ftHeight = GlobalSettings::self()->folderTreeHeight();
720  int headerHeight = GlobalSettings::self()->searchAndHeaderHeight();
721  const int messageViewerWidth = GlobalSettings::self()->readerWindowWidth();
722  int headerWidth = GlobalSettings::self()->searchAndHeaderWidth();
723  int messageViewerHeight = GlobalSettings::self()->readerWindowHeight();
724 
725  int ffvHeight = mFolderViewSplitter ? MailCommon::MailCommonSettings::self()->favoriteCollectionViewHeight() : 0;
726 
727  // If the message viewer was hidden before, make sure it is not zero height
728  if ( messageViewerHeight < 10 && readerWindowBelow ) {
729  headerHeight /= 2;
730  messageViewerHeight = headerHeight;
731  }
732 
733  if ( mLongFolderList ) {
734  if ( !readerWindowAtSide ) {
735  splitter1Sizes << folderViewWidth << headerWidth;
736  splitter2Sizes << headerHeight << messageViewerHeight;
737  } else {
738  splitter1Sizes << folderViewWidth << ( headerWidth + messageViewerWidth );
739  splitter2Sizes << headerWidth << messageViewerWidth;
740  }
741  } else {
742  if ( !readerWindowAtSide ) {
743  splitter1Sizes << headerHeight << messageViewerHeight;
744  splitter2Sizes << folderViewWidth << headerWidth;
745  } else {
746  splitter1Sizes << headerWidth << messageViewerWidth;
747  splitter2Sizes << ftHeight + ffvHeight << messageViewerHeight;
748  }
749  }
750 
751  mSplitter1->setSizes( splitter1Sizes );
752  mSplitter2->setSizes( splitter2Sizes );
753 
754  if ( mFolderViewSplitter ) {
755  QList<int> splitterSizes;
756  splitterSizes << ffvHeight << ftHeight;
757  mFolderViewSplitter->setSizes( splitterSizes );
758  }
759 
760  //
761  // Now add the splitters to the main layout
762  //
763  mTopLayout->addWidget( mSplitter1 );
764 
765  // Make sure the focus is on the view, and not on the quick search line edit, because otherwise
766  // shortcuts like + or j go to the wrong place.
767  // This would normally be done in the message list itself, but apparently something resets the focus
768  // again, probably all the reparenting we do here.
769  mMessagePane->focusView();
770 
771  // By default hide th unread and size columns on first run.
772  if ( kmkernel->firstStart() )
773  {
774  mFolderTreeWidget->folderTreeView()->hideColumn( 1 );
775  mFolderTreeWidget->folderTreeView()->hideColumn( 3 );
776  mFolderTreeWidget->folderTreeView()->header()->resizeSection( 0, folderViewWidth * 0.8 );
777  }
778 
779  // Make the copy action work, see disconnect comment above
780  if ( mMsgView )
781  connect( mMsgView->copyAction(), SIGNAL(triggered(bool)),
782  mMsgView, SLOT(slotCopySelectedText()) );
783 }
784 
785 //-----------------------------------------------------------------------------
786 void KMMainWidget::refreshFavoriteFoldersViewProperties()
787 {
788  if ( mFavoriteCollectionsView ) {
789  if ( MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode )
790  mFavoriteCollectionsView->changeViewMode( QListView::IconMode );
791  else if ( MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode )
792  mFavoriteCollectionsView->changeViewMode( QListView::ListMode );
793  else
794  Q_ASSERT(false); // we should never get here in hidden mode
795  mFavoriteCollectionsView->setDropActionMenuEnabled( kmkernel->showPopupAfterDnD() );
796  mFavoriteCollectionsView->setWordWrap( true );
797  mFavoriteCollectionsView->updateMode();
798  }
799 }
800 
801 //-----------------------------------------------------------------------------
802 void KMMainWidget::readConfig()
803 {
804  const bool oldLongFolderList = mLongFolderList;
805  const bool oldReaderWindowActive = mReaderWindowActive;
806  const bool oldReaderWindowBelow = mReaderWindowBelow;
807  const bool oldFavoriteFolderView = mEnableFavoriteFolderView;
808  const bool oldFolderQuickSearch = mEnableFolderQuickSearch;
809 
810  // on startup, the layout is always new and we need to relayout the widgets
811  bool layoutChanged = !mStartupDone;
812 
813  if ( mStartupDone )
814  {
815  readPreConfig();
816 
817  layoutChanged = ( oldLongFolderList != mLongFolderList ) ||
818  ( oldReaderWindowActive != mReaderWindowActive ) ||
819  ( oldReaderWindowBelow != mReaderWindowBelow ) ||
820  ( oldFavoriteFolderView != mEnableFavoriteFolderView );
821 
822  if ( layoutChanged ) {
823  deleteWidgets();
824  createWidgets();
825  restoreCollectionFolderViewConfig();
826  emit recreateGui();
827  } else if ( oldFolderQuickSearch != mEnableFolderQuickSearch ) {
828  if ( mEnableFolderQuickSearch )
829  mFolderTreeWidget->filterFolderLineEdit()->show();
830  else
831  mFolderTreeWidget->filterFolderLineEdit()->hide();
832  }
833  }
834 
835 
836  { // Read the config of the folder views and the header
837  if ( mMsgView ) {
838  mMsgView->readConfig();
839  }
840  mMessagePane->reloadGlobalConfiguration();
841  mFolderTreeWidget->readConfig();
842  if ( mFavoriteCollectionsView ) {
843  mFavoriteCollectionsView->readConfig();
844  }
845  refreshFavoriteFoldersViewProperties();
846  }
847 
848  { // area for config group "General"
849  if ( !mStartupDone )
850  {
851  // check mail on startup
852  // do it after building the kmmainwin, so that the progressdialog is available
853  QTimer::singleShot( 0, this, SLOT(slotCheckMailOnStartup()) );
854  }
855  }
856 
857  if ( layoutChanged ) {
858  layoutSplitters();
859  }
860 
861  updateMessageMenu();
862  updateFileMenu();
863  kmkernel->toggleSystemTray();
864 
865  connect( Akonadi::AgentManager::self(), SIGNAL(instanceAdded(Akonadi::AgentInstance)),
866  this, SLOT(updateFileMenu()) );
867  connect( Akonadi::AgentManager::self(), SIGNAL(instanceRemoved(Akonadi::AgentInstance)),
868  this, SLOT(updateFileMenu()) );
869 }
870 
871 //-----------------------------------------------------------------------------
872 void KMMainWidget::writeConfig(bool force)
873 {
874  // Don't save the sizes of all the widgets when we were never shown.
875  // This can happen in Kontact, where the KMail plugin is automatically
876  // loaded, but not necessarily shown.
877  // This prevents invalid sizes from being saved
878  if ( mWasEverShown ) {
879  // The height of the header widget can be 0, this happens when the user
880  // did not switch to the header widget onced and the "Welcome to KMail"
881  // HTML widget was shown the whole time
882  int headersHeight = mMessagePane->height();
883  if ( headersHeight == 0 )
884  headersHeight = height() / 2;
885 
886  GlobalSettings::self()->setSearchAndHeaderHeight( headersHeight );
887  GlobalSettings::self()->setSearchAndHeaderWidth( mMessagePane->width() );
888  if ( mFavoriteCollectionsView ) {
889  MailCommon::MailCommonSettings::self()->setFavoriteCollectionViewHeight( mFavoriteCollectionsView->height() );
890  GlobalSettings::self()->setFolderTreeHeight( mFolderTreeWidget->height() );
891  if ( !mLongFolderList ) {
892  GlobalSettings::self()->setFolderViewHeight( mFolderViewSplitter->height() );
893  }
894  }
895  else if ( !mLongFolderList && mFolderTreeWidget )
896  {
897  GlobalSettings::self()->setFolderTreeHeight( mFolderTreeWidget->height() );
898  }
899  if ( mFolderTreeWidget )
900  {
901  GlobalSettings::self()->setFolderViewWidth( mFolderTreeWidget->width() );
902  KSharedConfig::Ptr config = KMKernel::self()->config();
903  KConfigGroup group(config, "CollectionFolderView");
904 
905  ETMViewStateSaver saver;
906  saver.setView( mFolderTreeWidget->folderTreeView() );
907  saver.saveState( group );
908 
909  group.writeEntry( "HeaderState", mFolderTreeWidget->folderTreeView()->header()->saveState() );
910  //Work around from startup folder
911  group.deleteEntry( "Selection" );
912 #if 0
913  if (!GlobalSettings::self()->startSpecificFolderAtStartup()) {
914  group.deleteEntry( "Current" );
915  }
916 #endif
917  group.sync();
918  }
919 
920  if ( mMsgView ) {
921  if ( !mReaderWindowBelow )
922  GlobalSettings::self()->setReaderWindowWidth( mMsgView->width() );
923  mMsgView->viewer()->writeConfig(force);
924  GlobalSettings::self()->setReaderWindowHeight( mMsgView->height() );
925  }
926  }
927 }
928 
929 void KMMainWidget::writeReaderConfig()
930 {
931  if ( mWasEverShown ) {
932  if ( mMsgView ) {
933  mMsgView->viewer()->writeConfig();
934  }
935  }
936 }
937 
938 //-----------------------------------------------------------------------------
939 void KMMainWidget::deleteWidgets()
940 {
941  // Simply delete the top splitter, which always is mSplitter1, regardless
942  // of the layout. This deletes all children.
943  // akonadi action manager is created in createWidgets(), parented to this
944  // so not autocleaned up.
945  delete mAkonadiStandardActionManager;
946  mAkonadiStandardActionManager = 0;
947  delete mSplitter1;
948  mMsgView = 0;
949  mSearchAndTree = 0;
950  mFolderViewSplitter = 0;
951  mFavoriteCollectionsView = 0;
952  mSplitter1 = 0;
953  mSplitter2 = 0;
954  mFavoritesModel = 0;
955 }
956 
957 //-----------------------------------------------------------------------------
958 void KMMainWidget::createWidgets()
959 {
960  // Note that all widgets we create in this function have the parent 'this'.
961  // They will be properly reparented in layoutSplitters()
962 
963  //
964  // Create header view and search bar
965  //
966  FolderTreeWidget::TreeViewOptions opt = FolderTreeWidget::ShowUnreadCount;
967  opt |= FolderTreeWidget::UseLineEditForFiltering;
968  opt |= FolderTreeWidget::ShowCollectionStatisticAnimation;
969  opt |= FolderTreeWidget::DontKeyFilter;
970  mFolderTreeWidget = new FolderTreeWidget( this, mGUIClient, opt );
971 
972  connect( mFolderTreeWidget->folderTreeView(), SIGNAL(currentChanged(Akonadi::Collection)), this, SLOT(slotFolderChanged(Akonadi::Collection)) );
973 
974  connect( mFolderTreeWidget->folderTreeView()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateFolderMenu()) );
975 
976  connect( mFolderTreeWidget->folderTreeView(), SIGNAL(prefereCreateNewTab(bool)), this, SLOT(slotCreateNewTab(bool)) );
977 
978  mFolderTreeWidget->setSelectionMode( QAbstractItemView::ExtendedSelection );
979  mMessagePane = new CollectionPane( !GlobalSettings::self()->startSpecificFolderAtStartup(), KMKernel::self()->entityTreeModel(),
980  mFolderTreeWidget->folderTreeView()->selectionModel(),
981  this );
982  connect( KMKernel::self()->entityTreeModel(), SIGNAL(collectionFetched(int)), this, SLOT(slotCollectionFetched(int)));
983 
984  mMessagePane->setXmlGuiClient( mGUIClient );
985  connect( mMessagePane, SIGNAL(messageSelected(Akonadi::Item)),
986  this, SLOT(slotMessageSelected(Akonadi::Item)) );
987  connect( mMessagePane, SIGNAL(selectionChanged()),
988  SLOT(startUpdateMessageActionsTimer()) );
989  connect( mMessagePane, SIGNAL(currentTabChanged()), this, SLOT(refreshMessageListSelection()) );
990  connect( mMessagePane, SIGNAL(messageActivated(Akonadi::Item)),
991  this, SLOT(slotMessageActivated(Akonadi::Item)) );
992  connect( mMessagePane, SIGNAL(messageStatusChangeRequest(Akonadi::Item,Akonadi::MessageStatus,Akonadi::MessageStatus)),
993  SLOT(slotMessageStatusChangeRequest(Akonadi::Item,Akonadi::MessageStatus,Akonadi::MessageStatus)) );
994 
995  connect( mMessagePane, SIGNAL(statusMessage(QString)),
996  BroadcastStatus::instance(), SLOT(setStatusMsg(QString)) );
997 
998 
999  //
1000  // Create the reader window
1001  //
1002  if ( mReaderWindowActive ) {
1003  mMsgView = new KMReaderWin( this, this, actionCollection(), 0 );
1004  if ( mMsgActions ) {
1005  mMsgActions->setMessageView( mMsgView );
1006  }
1007  connect( mMsgView->viewer(), SIGNAL(replaceMsgByUnencryptedVersion()),
1008  this, SLOT(slotReplaceMsgByUnencryptedVersion()) );
1009  connect( mMsgView->viewer(), SIGNAL(popupMenu(Akonadi::Item,KUrl,KUrl,QPoint)),
1010  this, SLOT(slotMessagePopup(Akonadi::Item,KUrl,KUrl,QPoint)) );
1011  connect( mMsgView->viewer(), SIGNAL(moveMessageToTrash()),
1012  this, SLOT(slotMoveMessageToTrash()) );
1013  if (mShowIntroductionAction)
1014  mShowIntroductionAction->setEnabled(true);
1015  }
1016  else {
1017  if ( mMsgActions ) {
1018  mMsgActions->setMessageView( 0 );
1019  }
1020  if (mShowIntroductionAction)
1021  mShowIntroductionAction->setEnabled(false);
1022  }
1023 
1024  //
1025  // Create the folder tree
1026  // the "folder tree" consists of a quicksearch input field and the tree itself
1027  //
1028 
1029  mSearchAndTree = new QWidget( this );
1030  QVBoxLayout *vboxlayout = new QVBoxLayout;
1031  vboxlayout->setMargin(0);
1032  mSearchAndTree->setLayout( vboxlayout );
1033 
1034  vboxlayout->addWidget( mFolderTreeWidget );
1035 
1036  if ( !GlobalSettings::self()->enableFolderQuickSearch() ) {
1037  mFolderTreeWidget->filterFolderLineEdit()->hide();
1038  }
1039  //
1040  // Create the favorite folder view
1041  //
1042  mAkonadiStandardActionManager = new Akonadi::StandardMailActionManager( mGUIClient->actionCollection(), this );
1043  connect( mAkonadiStandardActionManager, SIGNAL(actionStateUpdated()), this, SLOT(slotAkonadiStandardActionUpdated()) );
1044 
1045  mAkonadiStandardActionManager->setCollectionSelectionModel( mFolderTreeWidget->folderTreeView()->selectionModel() );
1046  mAkonadiStandardActionManager->setItemSelectionModel( mMessagePane->currentItemSelectionModel() );
1047 
1048  if ( mEnableFavoriteFolderView ) {
1049 
1050  mFavoriteCollectionsView = new FavoriteCollectionWidget( mGUIClient, this );
1051  refreshFavoriteFoldersViewProperties();
1052 
1053  connect( mFavoriteCollectionsView, SIGNAL(currentChanged(Akonadi::Collection)), this, SLOT(slotFolderChanged(Akonadi::Collection)) );
1054 
1055  mFavoritesModel = new Akonadi::FavoriteCollectionsModel(
1056  mFolderTreeWidget->folderTreeView()->model(),
1057  KMKernel::self()->config()->group( "FavoriteCollections" ), this );
1058 
1059  mFavoriteCollectionsView->setModel( mFavoritesModel );
1060 
1061  mAkonadiStandardActionManager->setFavoriteCollectionsModel( mFavoritesModel );
1062  mAkonadiStandardActionManager->setFavoriteSelectionModel( mFavoriteCollectionsView->selectionModel() );
1063  }
1064 
1065  //Don't use mMailActionManager->createAllActions() to save memory by not
1066  //creating actions that doesn't make sense.
1067  QList<StandardActionManager::Type> standardActions;
1068  standardActions << StandardActionManager::CreateCollection
1069  << StandardActionManager::CopyCollections
1070  << StandardActionManager::DeleteCollections
1071  << StandardActionManager::SynchronizeCollections
1072  << StandardActionManager::CollectionProperties
1073  << StandardActionManager::CopyItems
1074  << StandardActionManager::Paste
1075  << StandardActionManager::DeleteItems
1076  << StandardActionManager::ManageLocalSubscriptions
1077  << StandardActionManager::CopyCollectionToMenu
1078  << StandardActionManager::CopyItemToMenu
1079  << StandardActionManager::MoveItemToMenu
1080  << StandardActionManager::MoveCollectionToMenu
1081  << StandardActionManager::CutItems
1082  << StandardActionManager::CutCollections
1083  << StandardActionManager::CreateResource
1084  << StandardActionManager::DeleteResources
1085  << StandardActionManager::ResourceProperties
1086  << StandardActionManager::SynchronizeResources
1087  << StandardActionManager::ToggleWorkOffline
1088  << StandardActionManager::SynchronizeCollectionsRecursive;
1089 
1090  Q_FOREACH( StandardActionManager::Type standardAction, standardActions ) {
1091  mAkonadiStandardActionManager->createAction( standardAction );
1092  }
1093 
1094 
1095  if (mEnableFavoriteFolderView) {
1096  QList<StandardActionManager::Type> favoriteActions;
1097  favoriteActions << StandardActionManager::AddToFavoriteCollections
1098  << StandardActionManager::RemoveFromFavoriteCollections
1099  << StandardActionManager::RenameFavoriteCollection
1100  << StandardActionManager::SynchronizeFavoriteCollections;
1101  Q_FOREACH( StandardActionManager::Type favoriteAction, favoriteActions) {
1102  mAkonadiStandardActionManager->createAction( favoriteAction );
1103  }
1104  }
1105 
1106  QList<StandardMailActionManager::Type> mailActions;
1107  mailActions << StandardMailActionManager::MarkAllMailAsRead
1108  << StandardMailActionManager::MoveToTrash
1109  << StandardMailActionManager::MoveAllToTrash
1110  << StandardMailActionManager::RemoveDuplicates
1111  << StandardMailActionManager::EmptyAllTrash
1112  << StandardMailActionManager::MarkMailAsRead
1113  << StandardMailActionManager::MarkMailAsUnread
1114  << StandardMailActionManager::MarkMailAsImportant
1115  << StandardMailActionManager::MarkMailAsActionItem;
1116 
1117  Q_FOREACH( StandardMailActionManager::Type mailAction, mailActions ) {
1118  mAkonadiStandardActionManager->createAction( mailAction );
1119  }
1120 
1121  mAkonadiStandardActionManager->interceptAction( Akonadi::StandardActionManager::CollectionProperties );
1122  connect( mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CollectionProperties ), SIGNAL(triggered(bool)), mManageShowCollectionProperties, SLOT(slotCollectionProperties()) );
1123 
1124 
1125  //
1126  // Create all kinds of actions
1127  //
1128  mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::RemoveDuplicates )->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Asterisk ) );
1129  mAkonadiStandardActionManager->interceptAction( Akonadi::StandardMailActionManager::RemoveDuplicates );
1130  connect( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::RemoveDuplicates ), SIGNAL(triggered(bool)), this, SLOT(slotRemoveDuplicates()) );
1131 
1132  {
1133  mCollectionProperties = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CollectionProperties );
1134  }
1135  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionRemoved(Akonadi::Collection)),
1136  SLOT(slotCollectionRemoved(Akonadi::Collection)) );
1137  connect( kmkernel->folderCollectionMonitor(), SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)),
1138  SLOT(slotItemAdded(Akonadi::Item,Akonadi::Collection)) );
1139  connect( kmkernel->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)),
1140  SLOT(slotItemRemoved(Akonadi::Item)) );
1141  connect( kmkernel->folderCollectionMonitor(), SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)),
1142  SLOT(slotItemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)) );
1143  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)), SLOT(slotCollectionChanged(Akonadi::Collection,QSet<QByteArray>)) );
1144 
1145  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), SLOT(slotCollectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)) );
1146 
1147 }
1148 
1149 void KMMainWidget::updateMoveAction( const Akonadi::CollectionStatistics& statistic )
1150 {
1151  const bool hasUnreadMails = (statistic.unreadCount() > 0);
1152  const bool hasMails = (statistic.count()>0);
1153  updateMoveAction(hasUnreadMails,hasMails);
1154 }
1155 
1156 void KMMainWidget::updateMoveAction( bool hasUnreadMails, bool hasMails )
1157 {
1158  const bool enable_goto_unread = hasUnreadMails
1159  || (GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders)
1160  || (GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders);
1161  actionCollection()->action( QLatin1String("go_next_message") )->setEnabled( hasMails );
1162  actionCollection()->action( QLatin1String("go_next_unread_message") )->setEnabled( enable_goto_unread );
1163  actionCollection()->action( QLatin1String("go_prev_message") )->setEnabled( hasMails );
1164  actionCollection()->action( QLatin1String("go_prev_unread_message") )->setEnabled( enable_goto_unread );
1165  if ( mAkonadiStandardActionManager && mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MarkAllMailAsRead ) ) {
1166  mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MarkAllMailAsRead )->setEnabled(hasUnreadMails);
1167  }
1168 }
1169 
1170 void KMMainWidget::updateAllToTrashAction(int statistics)
1171 {
1172  bool multiFolder = false;
1173  if ( mFolderTreeWidget ) {
1174  multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
1175  }
1176  if ( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash ) ) {
1177  const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural();
1178  mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash )->setEnabled( folderWithContent
1179  && ( statistics > 0 )
1180  && mCurrentFolder->canDeleteMessages()
1181  && !multiFolder );
1182  }
1183 }
1184 
1185 void KMMainWidget::slotCollectionStatisticsChanged( const Akonadi::Collection::Id id, const Akonadi::CollectionStatistics& statistic )
1186 {
1187  if ( id == CommonKernel->outboxCollectionFolder().id() ) {
1188  const bool enableAction = (statistic.count() > 0);
1189  mSendQueued->setEnabled( enableAction );
1190  mSendActionMenu->setEnabled( enableAction );
1191  } else if ( mCurrentFolder && ( id == mCurrentFolder->collection().id() ) ) {
1192  updateMoveAction( statistic );
1193  updateAllToTrashAction(statistic.count());
1194  mCurrentFolder->setCollection(MailCommon::Util::updatedCollection( mCurrentFolder->collection() ));
1195  }
1196 }
1197 
1198 void KMMainWidget::slotCreateNewTab( bool preferNewTab )
1199 {
1200  mMessagePane->setPreferEmptyTab( preferNewTab );
1201 }
1202 
1203 void KMMainWidget::slotCollectionChanged( const Akonadi::Collection&collection, const QSet<QByteArray>&set )
1204 {
1205  if ( mCurrentFolder
1206  && ( collection == mCurrentFolder->collection() )
1207  && ( set.contains( "MESSAGEFOLDER" ) || set.contains( "expirationcollectionattribute" ) ) ) {
1208  if ( set.contains( "MESSAGEFOLDER" ) )
1209  mMessagePane->resetModelStorage();
1210  else {
1211  mCurrentFolder->setCollection( collection );
1212  }
1213  } else if ( set.contains( "ENTITYDISPLAY" ) || set.contains( "NAME" ) ) {
1214  const QModelIndex idx = Akonadi::EntityTreeModel::modelIndexForCollection( KMKernel::self()->collectionModel(), collection );
1215  if ( idx.isValid() ) {
1216  const QString text = idx.data().toString();
1217  const QIcon icon = idx.data( Qt::DecorationRole ).value<QIcon>();
1218  mMessagePane->updateTabIconText( collection, text,icon );
1219  }
1220  }
1221 }
1222 
1223 
1224 void KMMainWidget::slotItemAdded( const Akonadi::Item &msg, const Akonadi::Collection &col )
1225 {
1226  Q_UNUSED(msg);
1227  if ( col.isValid() ) {
1228  if ( col == CommonKernel->outboxCollectionFolder() ) {
1229  startUpdateMessageActionsTimer();
1230  }
1231  }
1232 }
1233 
1234 void KMMainWidget::slotItemRemoved( const Akonadi::Item & item)
1235 {
1236  if ( item.isValid() && item.parentCollection().isValid() && ( item.parentCollection() == CommonKernel->outboxCollectionFolder() ) ) {
1237  startUpdateMessageActionsTimer();
1238  }
1239 }
1240 
1241 void KMMainWidget::slotItemMoved( const Akonadi::Item &item, const Akonadi::Collection &from, const Akonadi::Collection &to )
1242 {
1243  if ( item.isValid() && ( ( from.id() == CommonKernel->outboxCollectionFolder().id() )
1244  || to.id() == CommonKernel->outboxCollectionFolder().id() ) ) {
1245  startUpdateMessageActionsTimer();
1246  }
1247 }
1248 
1249 //-------------------------------------------------------------------------
1250 void KMMainWidget::slotFocusQuickSearch()
1251 {
1252  const QString text = mMsgView ? mMsgView->copyText() : QString();
1253  mMessagePane->focusQuickSearch(text);
1254 }
1255 
1256 //-------------------------------------------------------------------------
1257 bool KMMainWidget::slotSearch()
1258 {
1259  if (!mSearchWin)
1260  {
1261  mSearchWin = new SearchWindow(this, mCurrentFolder ? mCurrentFolder->collection() : Akonadi::Collection());
1262  mSearchWin->setModal( false );
1263  mSearchWin->setObjectName( QLatin1String("Search") );
1264  }
1265  else
1266  {
1267  mSearchWin->activateFolder(mCurrentFolder ? mCurrentFolder->collection() : Akonadi::Collection());
1268  }
1269 
1270  mSearchWin->show();
1271  KWindowSystem::activateWindow( mSearchWin->winId() );
1272  return true;
1273 }
1274 
1275 
1276 //-----------------------------------------------------------------------------
1277 void KMMainWidget::slotHelp()
1278 {
1279  KToolInvocation::invokeHelp();
1280 }
1281 
1282 
1283 //-----------------------------------------------------------------------------
1284 void KMMainWidget::slotFilter()
1285 {
1286  FilterIf->openFilterDialog( true );
1287 }
1288 
1289 void KMMainWidget::slotManageSieveScripts()
1290 {
1291  if ( !kmkernel->askToGoOnline() ) {
1292  return;
1293  }
1294  if (mManageSieveDialog)
1295  return;
1296 
1297  mManageSieveDialog = new KSieveUi::ManageSieveScriptsDialog;
1298  mManageSieveDialog->show();
1299 }
1300 
1301 //-----------------------------------------------------------------------------
1302 void KMMainWidget::slotCheckMail()
1303 {
1304  kmkernel->checkMail();
1305 }
1306 
1307 //-----------------------------------------------------------------------------
1308 void KMMainWidget::slotCheckMailOnStartup()
1309 {
1310  kmkernel->checkMailOnStartup();
1311 }
1312 
1313 //-----------------------------------------------------------------------------
1314 void KMMainWidget::slotCompose()
1315 {
1316  KMail::Composer * win;
1317  KMime::Message::Ptr msg( new KMime::Message() );
1318 
1319  bool forceCursorPosition = false;
1320  if ( mCurrentFolder ) {
1321  MessageHelper::initHeader( msg, KMKernel::self()->identityManager(), mCurrentFolder->identity() );
1322  //Laurent: bug 289905
1323  /*
1324  if ( mCurrentFolder->collection().isValid() && mCurrentFolder->putRepliesInSameFolder() ) {
1325  KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Fcc", msg.get(), QString::number( mCurrentFolder->collection().id() ), "utf-8" );
1326  msg->setHeader( header );
1327  }
1328  */
1329  TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage );
1330  parser.setIdentityManager( KMKernel::self()->identityManager() );
1331  parser.process( msg, mCurrentFolder->collection() );
1332  win = KMail::makeComposer( msg, false, false, KMail::Composer::New, mCurrentFolder->identity() );
1333  win->setCollectionForNewMessage( mCurrentFolder->collection() );
1334  forceCursorPosition = parser.cursorPositionWasSet();
1335  } else {
1336  MessageHelper::initHeader( msg, KMKernel::self()->identityManager() );
1337  TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage );
1338  parser.setIdentityManager( KMKernel::self()->identityManager() );
1339  parser.process( KMime::Message::Ptr(), Akonadi::Collection() );
1340  win = KMail::makeComposer( msg, false, false, KMail::Composer::New );
1341  forceCursorPosition = parser.cursorPositionWasSet();
1342  }
1343  if (forceCursorPosition) {
1344  win->setFocusToEditor();
1345  }
1346  win->show();
1347 
1348 }
1349 
1350 //-----------------------------------------------------------------------------
1351 // TODO: do we want the list sorted alphabetically?
1352 void KMMainWidget::slotShowNewFromTemplate()
1353 {
1354  if ( mCurrentFolder ) {
1355  const KPIMIdentities::Identity & ident =
1356  kmkernel->identityManager()->identityForUoidOrDefault( mCurrentFolder->identity() );
1357  mTemplateFolder = CommonKernel->collectionFromId( ident.templates().toLongLong() );
1358  }
1359 
1360  if ( !mTemplateFolder.isValid() ) {
1361  mTemplateFolder = CommonKernel->templatesCollectionFolder();
1362  }
1363  if ( !mTemplateFolder.isValid() )
1364  return;
1365 
1366  mTemplateMenu->menu()->clear();
1367 
1368  Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( mTemplateFolder );
1369  job->fetchScope().setAncestorRetrieval( ItemFetchScope::Parent );
1370  job->fetchScope().fetchFullPayload();
1371  connect( job, SIGNAL(result(KJob*)), SLOT(slotDelayedShowNewFromTemplate(KJob*)) );
1372 }
1373 
1374 void KMMainWidget::slotDelayedShowNewFromTemplate( KJob *job )
1375 {
1376  Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob*>( job );
1377 
1378  const Akonadi::Item::List items = fetchJob->items();
1379  const int numberOfItems = items.count();
1380  for ( int idx = 0; idx < numberOfItems; ++idx ) {
1381  KMime::Message::Ptr msg = MessageCore::Util::message( items.at( idx ) );
1382  if ( msg ) {
1383  QString subj = msg->subject()->asUnicodeString();
1384  if ( subj.isEmpty() )
1385  subj = i18n("No Subject");
1386 
1387  QAction *templateAction = mTemplateMenu->menu()->addAction(KStringHandler::rsqueeze( subj.replace( QLatin1Char('&'), QLatin1String("&&") ) ) );
1388  QVariant var;
1389  var.setValue( items.at( idx ) );
1390  templateAction->setData( var );
1391  }
1392  }
1393 
1394  // If there are no templates available, add a menu entry which informs
1395  // the user about this.
1396  if ( mTemplateMenu->menu()->actions().isEmpty() ) {
1397  QAction *noAction = mTemplateMenu->menu()->addAction(
1398  i18n( "(no templates)" ) );
1399  noAction->setEnabled( false );
1400  }
1401 }
1402 
1403 
1404 //-----------------------------------------------------------------------------
1405 void KMMainWidget::slotNewFromTemplate( QAction *action )
1406 {
1407 
1408  if ( !mTemplateFolder.isValid() )
1409  return;
1410  const Akonadi::Item item = action->data().value<Akonadi::Item>();
1411  newFromTemplate( item );
1412 }
1413 
1414 
1415 //-----------------------------------------------------------------------------
1416 void KMMainWidget::newFromTemplate( const Akonadi::Item &msg )
1417 {
1418  if ( !msg.isValid() )
1419  return;
1420  KMCommand *command = new KMUseTemplateCommand( this, msg );
1421  command->start();
1422 }
1423 
1424 
1425 //-----------------------------------------------------------------------------
1426 void KMMainWidget::slotPostToML()
1427 {
1428  if ( mCurrentFolder && mCurrentFolder->isMailingListEnabled() ) {
1429  if (KMail::Util::mailingListPost( mCurrentFolder )) {
1430  return;
1431  }
1432  }
1433  slotCompose();
1434 }
1435 
1436 //-----------------------------------------------------------------------------
1437 void KMMainWidget::slotExpireFolder()
1438 {
1439  if ( !mCurrentFolder )
1440  return;
1441  bool mustDeleteExpirationAttribute = false;
1442  MailCommon::ExpireCollectionAttribute *attr = MailCommon::Util::expirationCollectionAttribute( mCurrentFolder->collection(), mustDeleteExpirationAttribute );
1443  bool canBeExpired = true;
1444  if ( !attr->isAutoExpire() ) {
1445  canBeExpired = false;
1446  } else if ( attr->unreadExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever &&
1447  attr->readExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever ) {
1448  canBeExpired = false;
1449  }
1450 
1451  if ( !canBeExpired ) {
1452  const QString message = i18n( "This folder does not have any expiry options set" );
1453  KMessageBox::information( this, message );
1454  if ( mustDeleteExpirationAttribute )
1455  delete attr;
1456  return;
1457  }
1458 
1459  if ( GlobalSettings::self()->warnBeforeExpire() ) {
1460  const QString message = i18n( "<qt>Are you sure you want to expire the folder <b>%1</b>?</qt>",
1461  Qt::escape( mCurrentFolder->name() ) );
1462  if ( KMessageBox::warningContinueCancel( this, message, i18n( "Expire Folder" ),
1463  KGuiItem( i18n( "&Expire" ) ) )
1464  != KMessageBox::Continue ) {
1465  if ( mustDeleteExpirationAttribute )
1466  delete attr;
1467  return;
1468  }
1469  }
1470 
1471  MailCommon::Util::expireOldMessages( mCurrentFolder->collection(), true /*immediate*/ );
1472  if ( mustDeleteExpirationAttribute )
1473  delete attr;
1474 }
1475 
1476 //-----------------------------------------------------------------------------
1477 void KMMainWidget::slotEmptyFolder()
1478 {
1479  if (!mCurrentFolder) return;
1480  const bool isTrash = CommonKernel->folderIsTrash( mCurrentFolder->collection() );
1481  if ( GlobalSettings::self()->confirmBeforeEmpty() )
1482  {
1483  const QString title = (isTrash) ? i18n("Empty Trash") : i18n("Move to Trash");
1484  const QString text = (isTrash) ?
1485  i18n("Are you sure you want to empty the trash folder?") :
1486  i18n("<qt>Are you sure you want to move all messages from "
1487  "folder <b>%1</b> to the trash?</qt>", Qt::escape( mCurrentFolder->name() ) );
1488 
1489  if (KMessageBox::warningContinueCancel(this, text, title, KGuiItem( title, QLatin1String("user-trash")))
1490  != KMessageBox::Continue) return;
1491  }
1492 #ifndef QT_NO_CURSOR
1493  MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() );
1494 #endif
1495  slotMarkAll();
1496  if (isTrash) {
1497  /* Don't ask for confirmation again when deleting, the user has already
1498  confirmed. */
1499  slotDeleteMsg( false );
1500  }
1501  else
1502  slotTrashSelectedMessages();
1503 
1504  if (mMsgView)
1505  mMsgView->clearCache();
1506 
1507  if ( !isTrash )
1508  BroadcastStatus::instance()->setStatusMsg(i18n("Moved all messages to the trash"));
1509 
1510  updateMessageActions();
1511 
1512  // Disable empty trash/move all to trash action - we've just deleted/moved
1513  // all folder contents.
1514  mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash )->setEnabled( false );
1515 }
1516 
1517 //-----------------------------------------------------------------------------
1518 void KMMainWidget::slotArchiveFolder()
1519 {
1520  if ( mCurrentFolder && mCurrentFolder->collection().isValid() ) {
1521  KMail::ArchiveFolderDialog archiveDialog;
1522  archiveDialog.setFolder( mCurrentFolder->collection() );
1523  archiveDialog.exec();
1524  }
1525 }
1526 
1527 //-----------------------------------------------------------------------------
1528 void KMMainWidget::slotRemoveFolder()
1529 {
1530  if ( !mCurrentFolder ) return;
1531  if ( !mCurrentFolder->collection().isValid() ) return;
1532  if ( mCurrentFolder->isSystemFolder() ) return;
1533  if ( mCurrentFolder->isReadOnly() ) return;
1534 
1535  RemoveCollectionJob *job = new RemoveCollectionJob(this);
1536  connect(job, SIGNAL(clearCurrentFolder()), this, SLOT(slotClearCurrentFolder()));
1537  job->setMainWidget(this);
1538  job->setCurrentFolder(mCurrentFolder->collection());
1539  job->start();
1540 }
1541 
1542 void KMMainWidget::slotClearCurrentFolder()
1543 {
1544  mCurrentFolder.clear();
1545 }
1546 
1547 //-----------------------------------------------------------------------------
1548 void KMMainWidget::slotExpireAll()
1549 {
1550  if ( GlobalSettings::self()->warnBeforeExpire() ) {
1551  const int ret = KMessageBox::warningContinueCancel(KMainWindow::memberList().first(),
1552  i18n("Are you sure you want to expire all old messages?"),
1553  i18n("Expire Old Messages?"), KGuiItem(i18n("Expire")));
1554  if (ret != KMessageBox::Continue) {
1555  return;
1556  }
1557  }
1558 
1559  kmkernel->expireAllFoldersNow();
1560 }
1561 
1562 
1563 //-----------------------------------------------------------------------------
1564 void KMMainWidget::slotOverrideHtmlLoadExt()
1565 {
1566  if ( mHtmlLoadExtGlobalSetting == mFolderHtmlLoadExtPreference ) {
1567  int result = KMessageBox::warningContinueCancel( this,
1568  // the warning text is taken from configuredialog.cpp:
1569  i18n( "Loading external references in html mail will make you more vulnerable to "
1570  "\"spam\" and may increase the likelihood that your system will be "
1571  "compromised by other present and anticipated security exploits." ),
1572  i18n( "Security Warning" ),
1573  KGuiItem(i18n( "Load External References" )),
1574  KStandardGuiItem::cancel(),
1575  QLatin1String("OverrideHtmlLoadExtWarning"), 0);
1576  if ( result == KMessageBox::Cancel ) {
1577  mPreferHtmlLoadExtAction->setChecked( false );
1578  return;
1579  }
1580  }
1581  mFolderHtmlLoadExtPreference = !mFolderHtmlLoadExtPreference;
1582 
1583  if (mMsgView) {
1584  mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
1585  mMsgView->update( true );
1586  }
1587 }
1588 
1589 //-----------------------------------------------------------------------------
1590 void KMMainWidget::slotMessageQueuedOrDrafted()
1591 {
1592  if (!CommonKernel->folderIsDraftOrOutbox(mCurrentFolder->collection()))
1593  return;
1594  if (mMsgView)
1595  mMsgView->update(true);
1596 }
1597 
1598 
1599 //-----------------------------------------------------------------------------
1600 void KMMainWidget::slotForwardInlineMsg()
1601 {
1602  if ( !mCurrentFolder ) {
1603  return;
1604  }
1605 
1606  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
1607  if ( selectedMessages.isEmpty() )
1608  return;
1609  KMForwardCommand * command = new KMForwardCommand(
1610  this, selectedMessages, mCurrentFolder->identity()
1611  );
1612 
1613  command->start();
1614 }
1615 
1616 
1617 //-----------------------------------------------------------------------------
1618 void KMMainWidget::slotForwardAttachedMsg()
1619 {
1620  if ( !mCurrentFolder ) {
1621  return;
1622  }
1623 
1624  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
1625  if ( selectedMessages.isEmpty() )
1626  return;
1627  KMForwardAttachedCommand * command = new KMForwardAttachedCommand(
1628  this, selectedMessages, mCurrentFolder->identity()
1629  );
1630 
1631  command->start();
1632 }
1633 
1634 
1635 //-----------------------------------------------------------------------------
1636 void KMMainWidget::slotUseTemplate()
1637 {
1638  newFromTemplate( mMessagePane->currentItem() );
1639 }
1640 
1641 
1642 //-----------------------------------------------------------------------------
1643 void KMMainWidget::slotResendMsg()
1644 {
1645  const Akonadi::Item msg = mMessagePane->currentItem();
1646  if ( !msg.isValid() )
1647  return;
1648  KMCommand *command = new KMResendMessageCommand( this, msg );
1649 
1650  command->start();
1651 }
1652 
1653 //-----------------------------------------------------------------------------
1654 // Message moving and permanent deletion
1655 //
1656 
1657 void KMMainWidget::moveMessageSelected( MessageList::Core::MessageItemSetReference ref, const Akonadi::Collection &dest, bool confirmOnDeletion )
1658 {
1659  QList<Akonadi::Item> selectMsg = mMessagePane->itemListFromPersistentSet( ref );
1660  // If this is a deletion, ask for confirmation
1661  if ( !dest.isValid() && confirmOnDeletion )
1662  {
1663  int ret = KMessageBox::warningContinueCancel(
1664  this,
1665  i18np(
1666  "<qt>Do you really want to delete the selected message?<br />"
1667  "Once deleted, it cannot be restored.</qt>",
1668  "<qt>Do you really want to delete the %1 selected messages?<br />"
1669  "Once deleted, they cannot be restored.</qt>",
1670  selectMsg.count()
1671  ),
1672  selectMsg.count() > 1 ? i18n( "Delete Messages" ) : i18n( "Delete Message" ),
1673  KStandardGuiItem::del(),
1674  KStandardGuiItem::cancel(),
1675  QLatin1String("NoConfirmDelete")
1676  );
1677  if ( ret == KMessageBox::Cancel )
1678  {
1679  mMessagePane->deletePersistentSet( ref );
1680  return; // user canceled the action
1681  }
1682  }
1683  mMessagePane->markMessageItemsAsAboutToBeRemoved( ref, true );
1684  // And stuff them into a KMMoveCommand :)
1685  KMMoveCommand *command = new KMMoveCommand( dest, selectMsg,ref );
1686  QObject::connect(
1687  command, SIGNAL(moveDone(KMMoveCommand*)),
1688  this, SLOT(slotMoveMessagesCompleted(KMMoveCommand*))
1689  );
1690  command->start();
1691 
1692  if ( dest.isValid() )
1693  BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages..." ) );
1694  else
1695  BroadcastStatus::instance()->setStatusMsg( i18n( "Deleting messages..." ) );
1696 }
1697 
1698 void KMMainWidget::slotMoveMessagesCompleted( KMMoveCommand *command )
1699 {
1700  Q_ASSERT( command );
1701  mMessagePane->markMessageItemsAsAboutToBeRemoved( command->refSet(), false );
1702  mMessagePane->deletePersistentSet( command->refSet() );
1703  // Bleah :D
1704  const bool moveWasReallyADelete = !command->destFolder().isValid();
1705 
1706  if ( command->result() == KMCommand::OK )
1707  {
1708  if ( moveWasReallyADelete )
1709  BroadcastStatus::instance()->setStatusMsg( i18n( "Messages deleted successfully." ) );
1710  else
1711  BroadcastStatus::instance()->setStatusMsg( i18n( "Messages moved successfully." ) );
1712  } else {
1713  if ( moveWasReallyADelete )
1714  {
1715  if ( command->result() == KMCommand::Failed )
1716  BroadcastStatus::instance()->setStatusMsg( i18n( "Deleting messages failed." ) );
1717  else
1718  BroadcastStatus::instance()->setStatusMsg( i18n( "Deleting messages canceled." ) );
1719  } else {
1720  if ( command->result() == KMCommand::Failed )
1721  BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages failed." ) );
1722  else
1723  BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages canceled." ) );
1724  }
1725  }
1726  // The command will autodelete itself and will also kill the set.
1727 }
1728 
1729 void KMMainWidget::slotDeleteMsg( bool confirmDelete )
1730 {
1731  // Create a persistent message set from the current selection
1732  MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1733  if ( ref != -1 )
1734  moveMessageSelected( ref, Akonadi::Collection(), confirmDelete );
1735 }
1736 
1737 void KMMainWidget::slotDeleteThread( bool confirmDelete )
1738 {
1739  // Create a persistent set from the current thread.
1740  MessageList::Core::MessageItemSetReference ref = mMessagePane->currentThreadAsPersistentSet();
1741  if ( ref != -1 )
1742  moveMessageSelected( ref, Akonadi::Collection(), confirmDelete );
1743 }
1744 
1745 FolderSelectionDialog* KMMainWidget::moveOrCopyToDialog()
1746 {
1747  if ( !mMoveOrCopyToDialog ) {
1748  FolderSelectionDialog::SelectionFolderOption options = FolderSelectionDialog::HideVirtualFolder;
1749  mMoveOrCopyToDialog = new FolderSelectionDialog( this, options );
1750  mMoveOrCopyToDialog->setModal( true );
1751  }
1752  return mMoveOrCopyToDialog;
1753 }
1754 
1755 FolderSelectionDialog* KMMainWidget::selectFromAllFoldersDialog()
1756 {
1757  if ( !mSelectFromAllFoldersDialog ) {
1758  FolderSelectionDialog::SelectionFolderOptions options = FolderSelectionDialog::None;
1759  options |= FolderSelectionDialog::NotAllowToCreateNewFolder;
1760 
1761  mSelectFromAllFoldersDialog = new FolderSelectionDialog( this, options );
1762  mSelectFromAllFoldersDialog->setModal( true );
1763  }
1764  return mSelectFromAllFoldersDialog;
1765 }
1766 
1767 void KMMainWidget::slotMoveSelectedMessageToFolder()
1768 {
1769  QPointer<MailCommon::FolderSelectionDialog> dialog( moveOrCopyToDialog() );
1770  dialog->setCaption( i18n( "Move Messages to Folder" ) );
1771  if ( dialog->exec() && dialog ) {
1772  const Akonadi::Collection dest = dialog->selectedCollection();
1773  if ( dest.isValid() ) {
1774  moveSelectedMessagesToFolder( dest );
1775  }
1776  }
1777 }
1778 
1779 void KMMainWidget::moveSelectedMessagesToFolder( const Akonadi::Collection & dest )
1780 {
1781  MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1782  if ( ref != -1 ) {
1783  //Need to verify if dest == src ??? akonadi do it for us.
1784  moveMessageSelected( ref, dest, false );
1785  }
1786 }
1787 
1788 
1789 void KMMainWidget::copyMessageSelected( const QList<Akonadi::Item> &selectMsg, const Akonadi::Collection &dest )
1790 {
1791  if ( selectMsg.isEmpty() )
1792  return;
1793  // And stuff them into a KMCopyCommand :)
1794  KMCommand *command = new KMCopyCommand( dest, selectMsg );
1795  QObject::connect(
1796  command, SIGNAL(completed(KMCommand*)),
1797  this, SLOT(slotCopyMessagesCompleted(KMCommand*))
1798  );
1799  command->start();
1800  BroadcastStatus::instance()->setStatusMsg( i18n( "Copying messages..." ) );
1801 }
1802 
1803 
1804 void KMMainWidget::slotCopyMessagesCompleted( KMCommand *command )
1805 {
1806  Q_ASSERT( command );
1807  if ( command->result() == KMCommand::OK )
1808  {
1809  BroadcastStatus::instance()->setStatusMsg( i18n( "Messages copied successfully." ) );
1810  } else {
1811  if ( command->result() == KMCommand::Failed )
1812  BroadcastStatus::instance()->setStatusMsg( i18n( "Copying messages failed." ) );
1813  else
1814  BroadcastStatus::instance()->setStatusMsg( i18n( "Copying messages canceled." ) );
1815  }
1816  // The command will autodelete itself and will also kill the set.
1817 }
1818 
1819 void KMMainWidget::slotCopySelectedMessagesToFolder()
1820 {
1821  QPointer<MailCommon::FolderSelectionDialog> dialog( moveOrCopyToDialog() );
1822  dialog->setCaption( i18n( "Copy Messages to Folder" ) );
1823 
1824  if ( dialog->exec() && dialog ) {
1825  const Akonadi::Collection dest = dialog->selectedCollection();
1826  if ( dest.isValid() ) {
1827  copySelectedMessagesToFolder( dest );
1828  }
1829  }
1830 }
1831 
1832 void KMMainWidget::copySelectedMessagesToFolder( const Akonadi::Collection& dest )
1833 {
1834  const QList<Akonadi::Item > lstMsg = mMessagePane->selectionAsMessageItemList();
1835  if ( !lstMsg.isEmpty() ) {
1836  copyMessageSelected( lstMsg, dest );
1837  }
1838 }
1839 
1840 //-----------------------------------------------------------------------------
1841 // Message trashing
1842 //
1843 void KMMainWidget::trashMessageSelected( MessageList::Core::MessageItemSetReference ref )
1844 {
1845  if ( !mCurrentFolder ) {
1846  return;
1847  }
1848 
1849  const QList<Akonadi::Item> select = mMessagePane->itemListFromPersistentSet( ref );
1850  mMessagePane->markMessageItemsAsAboutToBeRemoved( ref, true );
1851 
1852  // FIXME: Why we don't use KMMoveCommand( trashFolder(), selectedMessages ); ?
1853  // And stuff them into a KMTrashMsgCommand :)
1854  KMCommand *command = new KMTrashMsgCommand( mCurrentFolder->collection(), select,ref );
1855 
1856  QObject::connect(
1857  command, SIGNAL(moveDone(KMMoveCommand*)),
1858  this, SLOT(slotTrashMessagesCompleted(KMMoveCommand*))
1859  );
1860  command->start();
1861  BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages to trash..." ) );
1862 }
1863 
1864 void KMMainWidget::slotTrashMessagesCompleted( KMMoveCommand *command )
1865 {
1866  Q_ASSERT( command );
1867  mMessagePane->markMessageItemsAsAboutToBeRemoved( command->refSet(), false );
1868  mMessagePane->deletePersistentSet( command->refSet() );
1869  if ( command->result() == KMCommand::OK )
1870  {
1871  BroadcastStatus::instance()->setStatusMsg( i18n( "Messages moved to trash successfully." ) );
1872  } else {
1873  if ( command->result() == KMCommand::Failed ) {
1874  BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages to trash failed." ) );
1875  } else
1876  BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages to trash canceled." ) );
1877  }
1878 
1879  // The command will autodelete itself and will also kill the set.
1880 }
1881 
1882 void KMMainWidget::slotTrashSelectedMessages()
1883 {
1884  MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1885  if ( ref != -1 ) {
1886  trashMessageSelected( ref );
1887  }
1888 }
1889 
1890 void KMMainWidget::slotTrashThread()
1891 {
1892  MessageList::Core::MessageItemSetReference ref = mMessagePane->currentThreadAsPersistentSet();
1893  if ( ref != -1 )
1894  trashMessageSelected( ref );
1895 }
1896 
1897 //-----------------------------------------------------------------------------
1898 // Message tag setting for messages
1899 //
1900 // FIXME: The "selection" version of these functions is in MessageActions.
1901 // We should probably move everything there....
1902 void KMMainWidget::toggleMessageSetTag( const QList<Akonadi::Item> &select, const Akonadi::Tag &tag )
1903 {
1904  if ( select.isEmpty() )
1905  return;
1906  KMCommand *command = new KMSetTagCommand( Akonadi::Tag::List() << tag, select, KMSetTagCommand::Toggle );
1907  command->start();
1908 }
1909 
1910 
1911 void KMMainWidget::slotSelectMoreMessageTagList()
1912 {
1913  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
1914  if ( selectedMessages.isEmpty() )
1915  return;
1916 
1917  TagSelectDialog dlg( this, selectedMessages.count(), selectedMessages.first() );
1918  dlg.setActionCollection(QList<KActionCollection*>() << actionCollection());
1919  if ( dlg.exec() ) {
1920  const Akonadi::Tag::List lst = dlg.selectedTag();
1921  KMCommand *command = new KMSetTagCommand( lst, selectedMessages, KMSetTagCommand::CleanExistingAndAddNew );
1922  command->start();
1923  }
1924 }
1925 
1926 
1927 void KMMainWidget::slotUpdateMessageTagList( const Akonadi::Tag &tag )
1928 {
1929  // Create a persistent set from the current thread.
1930  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
1931  if ( selectedMessages.isEmpty() )
1932  return;
1933  toggleMessageSetTag( selectedMessages, tag );
1934 }
1935 
1936 void KMMainWidget::refreshMessageListSelection()
1937 {
1938  mAkonadiStandardActionManager->setItemSelectionModel( mMessagePane->currentItemSelectionModel() );
1939  slotMessageSelected(mMessagePane->currentItem());
1940 }
1941 
1942 //-----------------------------------------------------------------------------
1943 // Status setting for threads
1944 //
1945 // FIXME: The "selection" version of these functions is in MessageActions.
1946 // We should probably move everything there....
1947 void KMMainWidget::setMessageSetStatus( const QList<Akonadi::Item> &select,
1948  const Akonadi::MessageStatus &status,
1949  bool toggle )
1950 {
1951  KMCommand *command = new KMSetStatusCommand( status, select, toggle );
1952  command->start();
1953 }
1954 
1955 void KMMainWidget::setCurrentThreadStatus( const Akonadi::MessageStatus &status, bool toggle )
1956 {
1957  const QList<Akonadi::Item> select = mMessagePane->currentThreadAsMessageList();
1958  if ( select.isEmpty() )
1959  return;
1960  setMessageSetStatus( select, status, toggle );
1961 }
1962 
1963 void KMMainWidget::slotSetThreadStatusUnread()
1964 {
1965  setCurrentThreadStatus( MessageStatus::statusRead(), true );
1966 }
1967 
1968 void KMMainWidget::slotSetThreadStatusImportant()
1969 {
1970  setCurrentThreadStatus( MessageStatus::statusImportant(), true );
1971 }
1972 
1973 void KMMainWidget::slotSetThreadStatusRead()
1974 {
1975  setCurrentThreadStatus( MessageStatus::statusRead(), false );
1976 }
1977 
1978 void KMMainWidget::slotSetThreadStatusToAct()
1979 {
1980  setCurrentThreadStatus( MessageStatus::statusToAct(), true );
1981 }
1982 
1983 void KMMainWidget::slotSetThreadStatusWatched()
1984 {
1985  setCurrentThreadStatus( MessageStatus::statusWatched(), true );
1986  if ( mWatchThreadAction->isChecked() )
1987  mIgnoreThreadAction->setChecked(false);
1988 }
1989 
1990 void KMMainWidget::slotSetThreadStatusIgnored()
1991 {
1992  setCurrentThreadStatus( MessageStatus::statusIgnored(), true );
1993  if ( mIgnoreThreadAction->isChecked() )
1994  mWatchThreadAction->setChecked(false);
1995 }
1996 
1997 //-----------------------------------------------------------------------------
1998 void KMMainWidget::slotRedirectMsg()
1999 {
2000  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
2001  if ( selectedMessages.isEmpty() )
2002  return;
2003 
2004  KMCommand *command = new KMRedirectCommand( this, selectedMessages );
2005  command->start();
2006 }
2007 
2008 
2009 //-----------------------------------------------------------------------------
2010 void KMMainWidget::slotCustomReplyToMsg( const QString &tmpl )
2011 {
2012  const Akonadi::Item msg = mMessagePane->currentItem();
2013  if ( !msg.isValid() )
2014  return;
2015 
2016  const QString text = mMsgView ? mMsgView->copyText() : QString();
2017 
2018  kDebug() << "Reply with template:" << tmpl;
2019 
2020  KMCommand *command = new KMReplyCommand( this,
2021  msg,
2022  MessageComposer::ReplySmart,
2023  text, false,
2024  tmpl );
2025  command->start();
2026 }
2027 
2028 
2029 //-----------------------------------------------------------------------------
2030 void KMMainWidget::slotCustomReplyAllToMsg( const QString &tmpl )
2031 {
2032  const Akonadi::Item msg = mMessagePane->currentItem();
2033  if ( !msg.isValid() )
2034  return;
2035 
2036  const QString text = mMsgView? mMsgView->copyText() : QString();
2037 
2038  kDebug() << "Reply to All with template:" << tmpl;
2039 
2040  KMCommand *command = new KMReplyCommand(this,
2041  msg,
2042  MessageComposer::ReplyAll,
2043  text,
2044  false,
2045  tmpl
2046  );
2047 
2048  command->start();
2049 }
2050 
2051 
2052 //-----------------------------------------------------------------------------
2053 void KMMainWidget::slotCustomForwardMsg( const QString &tmpl )
2054 {
2055  if ( !mCurrentFolder ) {
2056  return;
2057  }
2058 
2059  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
2060  if ( selectedMessages.isEmpty() )
2061  return;
2062 
2063  kDebug() << "Forward with template:" << tmpl;
2064  KMForwardCommand * command = new KMForwardCommand(
2065  this, selectedMessages, mCurrentFolder->identity(), tmpl
2066  );
2067 
2068  command->start();
2069 }
2070 
2071 
2072 void KMMainWidget::openFilterDialog(const QByteArray &field, const QString &value)
2073 {
2074  FilterIf->openFilterDialog( false );
2075  FilterIf->createFilter( field, value );
2076 }
2077 
2078 //-----------------------------------------------------------------------------
2079 void KMMainWidget::slotSubjectFilter()
2080 {
2081  const KMime::Message::Ptr msg = mMessagePane->currentMessage();
2082  if ( !msg )
2083  return;
2084 
2085  openFilterDialog("Subject", msg->subject()->asUnicodeString());
2086 }
2087 
2088 //-----------------------------------------------------------------------------
2089 void KMMainWidget::slotFromFilter()
2090 {
2091  KMime::Message::Ptr msg = mMessagePane->currentMessage();
2092  if ( !msg )
2093  return;
2094 
2095  AddrSpecList al = MessageHelper::extractAddrSpecs( msg, "From" );
2096  if ( al.empty() )
2097  openFilterDialog("From", msg->from()->asUnicodeString());
2098  else
2099  openFilterDialog("From", al.front().asString());
2100 }
2101 
2102 //-----------------------------------------------------------------------------
2103 void KMMainWidget::slotToFilter()
2104 {
2105  KMime::Message::Ptr msg = mMessagePane->currentMessage();
2106  if ( !msg )
2107  return;
2108  openFilterDialog("To", msg->to()->asUnicodeString());
2109 }
2110 
2111 //-----------------------------------------------------------------------------
2112 void KMMainWidget::slotUndo()
2113 {
2114  kmkernel->undoStack()->undo();
2115  updateMessageActions();
2116  updateFolderMenu();
2117 }
2118 
2119 
2120 //-----------------------------------------------------------------------------
2121 void KMMainWidget::slotJumpToFolder()
2122 {
2123  QPointer<MailCommon::FolderSelectionDialog> dialog( selectFromAllFoldersDialog() );
2124  dialog->setCaption( i18n( "Jump to Folder") );
2125  if ( dialog->exec() && dialog ) {
2126  Akonadi::Collection collection = dialog->selectedCollection();
2127  if ( collection.isValid() ) {
2128  slotSelectCollectionFolder( collection );
2129  }
2130  }
2131 }
2132 
2133 void KMMainWidget::slotSelectCollectionFolder( const Akonadi::Collection & col )
2134 {
2135  if ( mFolderTreeWidget ) {
2136  mFolderTreeWidget->selectCollectionFolder( col );
2137  slotFolderChanged( col );
2138  }
2139 }
2140 
2141 void KMMainWidget::slotApplyFilters()
2142 {
2143  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
2144  if ( selectedMessages.isEmpty() )
2145  return;
2146  applyFilters( selectedMessages );
2147 }
2148 
2149 void KMMainWidget::slotApplyFiltersOnFolder()
2150 {
2151  if ( mCurrentFolder && mCurrentFolder->collection().isValid() ) {
2152  Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( mCurrentFolder->collection(), this );
2153  connect( job, SIGNAL(result(KJob*)), this, SLOT(slotFetchItemsForFolderDone(KJob*)) );
2154  }
2155 }
2156 
2157 void KMMainWidget::slotFetchItemsForFolderDone(KJob*job)
2158 {
2159  Akonadi::ItemFetchJob *fjob = dynamic_cast<Akonadi::ItemFetchJob*>( job );
2160  Q_ASSERT( fjob );
2161  Akonadi::Item::List items = fjob->items();
2162  applyFilters( items );
2163 }
2164 
2165 void KMMainWidget::applyFilters( const QList<Akonadi::Item>& selectedMessages )
2166 {
2167 #ifndef QT_NO_CURSOR
2168  MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() );
2169 #endif
2170 
2171  MailCommon::FilterManager::instance()->filter( selectedMessages );
2172 }
2173 
2174 //-----------------------------------------------------------------------------
2175 void KMMainWidget::slotCheckVacation()
2176 {
2177  updateVacationScriptStatus( false );
2178  if ( !kmkernel->askToGoOnline() )
2179  return;
2180 
2181  mVacationManager->checkVacation();
2182  connect(mVacationManager, SIGNAL(updateVacationScriptStatus(bool,QString)), SLOT(updateVacationScriptStatus(bool,QString)) );
2183  connect(mVacationManager, SIGNAL(editVacation()), SLOT(slotEditVacation()) );
2184 }
2185 
2186 void KMMainWidget::slotEditVacation(const QString &serverName)
2187 {
2188  if ( !kmkernel->askToGoOnline() ) {
2189  return;
2190  }
2191 
2192  mVacationManager->slotEditVacation(serverName);
2193 }
2194 
2195 //-----------------------------------------------------------------------------
2196 void KMMainWidget::slotDebugSieve()
2197 {
2198 #if !defined(NDEBUG)
2199  if ( mSieveDebugDialog )
2200  return;
2201 
2202  mSieveDebugDialog = new KSieveUi::SieveDebugDialog( this );
2203  mSieveDebugDialog->exec();
2204  delete mSieveDebugDialog;
2205 #endif
2206 }
2207 
2208 //-----------------------------------------------------------------------------
2209 void KMMainWidget::slotConfigChanged()
2210 {
2211  readConfig();
2212  mMsgActions->setupForwardActions();
2213  mMsgActions->setupForwardingActionsList( mGUIClient );
2214 }
2215 
2216 //-----------------------------------------------------------------------------
2217 void KMMainWidget::slotSaveMsg()
2218 {
2219  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
2220  if ( selectedMessages.isEmpty() )
2221  return;
2222  KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( this, selectedMessages );
2223  saveCommand->start();
2224 }
2225 
2226 //-----------------------------------------------------------------------------
2227 void KMMainWidget::slotOpenMsg()
2228 {
2229  KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( this, KUrl(), overrideEncoding(), this );
2230 
2231  openCommand->start();
2232 }
2233 
2234 //-----------------------------------------------------------------------------
2235 void KMMainWidget::slotSaveAttachments()
2236 {
2237  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
2238  if ( selectedMessages.isEmpty() )
2239  return;
2240  // Avoid re-downloading in the common case that only one message is selected, and the message
2241  // is also displayed in the viewer. For this, create a dummy item without a parent collection / item id,
2242  // so that KMCommand doesn't download it.
2243  KMSaveAttachmentsCommand *saveCommand = 0;
2244  if ( mMsgView && selectedMessages.size() == 1 &&
2245  mMsgView->message().hasPayload<KMime::Message::Ptr>() &&
2246  selectedMessages.first().id() == mMsgView->message().id() ) {
2247  Akonadi::Item dummyItem;
2248  dummyItem.setPayload<KMime::Message::Ptr>( mMsgView->message().payload<KMime::Message::Ptr>() );
2249  saveCommand = new KMSaveAttachmentsCommand( this, dummyItem, mMsgView->viewer() );
2250  } else {
2251  saveCommand = new KMSaveAttachmentsCommand( this, selectedMessages );
2252  }
2253 
2254  saveCommand->start();
2255 }
2256 
2257 void KMMainWidget::slotOnlineStatus()
2258 {
2259  // KMKernel will emit a signal when we toggle the network state that is caught by
2260  // KMMainWidget::slotUpdateOnlineStatus to update our GUI
2261  if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online ) {
2262  // if online; then toggle and set it offline.
2263  kmkernel->stopNetworkJobs();
2264  } else {
2265  kmkernel->resumeNetworkJobs();
2266  slotCheckVacation();
2267  }
2268 }
2269 
2270 void KMMainWidget::slotUpdateOnlineStatus( GlobalSettings::EnumNetworkState::type )
2271 {
2272  if ( !mAkonadiStandardActionManager ) {
2273  return;
2274  }
2275  KAction * action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::ToggleWorkOffline );
2276  if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online ) {
2277  action->setText( i18n("Work Offline") );
2278  action->setIcon( KIcon(QLatin1String("user-offline")) );
2279  } else {
2280  action->setText( i18n("Work Online") );
2281  action->setIcon( KIcon(QLatin1String("user-online")) );
2282  }
2283 }
2284 
2285 
2286 //-----------------------------------------------------------------------------
2287 void KMMainWidget::slotSendQueued()
2288 {
2289  if ( kmkernel->msgSender() ) {
2290  kmkernel->msgSender()->sendQueued();
2291  }
2292 }
2293 
2294 //-----------------------------------------------------------------------------
2295 void KMMainWidget::slotSendQueuedVia(MailTransport::Transport *transport)
2296 {
2297  if (transport) {
2298  if ( kmkernel->msgSender() ) {
2299  kmkernel->msgSender()->sendQueued( transport->id() );
2300  }
2301  }
2302 }
2303 
2304 //-----------------------------------------------------------------------------
2305 void KMMainWidget::slotShowBusySplash()
2306 {
2307  if ( mReaderWindowActive ) {
2308  mMsgView->displayBusyPage();
2309  }
2310 }
2311 
2312 void KMMainWidget::showOfflinePage()
2313 {
2314  if ( !mReaderWindowActive ) return;
2315 
2316  mMsgView->displayOfflinePage();
2317 }
2318 
2319 void KMMainWidget::showResourceOfflinePage()
2320 {
2321  if ( !mReaderWindowActive ) return;
2322 
2323  mMsgView->displayResourceOfflinePage();
2324 }
2325 
2326 
2327 //-----------------------------------------------------------------------------
2328 void KMMainWidget::slotReplaceMsgByUnencryptedVersion()
2329 {
2330  kDebug();
2331  Akonadi::Item oldMsg = mMessagePane->currentItem();
2332  if ( oldMsg.isValid() ) {
2333 #if 0
2334  kDebug() << "Old message found";
2335  if ( oldMsg->hasUnencryptedMsg() ) {
2336  kDebug() << "Extra unencrypted message found";
2337  KMime::Message* newMsg = oldMsg->unencryptedMsg();
2338  // adjust the message id
2339  {
2340  QString msgId( oldMsg->msgId() );
2341  QString prefix("DecryptedMsg.");
2342  int oldIdx = msgId.indexOf(prefix, 0, Qt::CaseInsensitive);
2343  if ( -1 == oldIdx ) {
2344  int leftAngle = msgId.lastIndexOf( '<' );
2345  msgId = msgId.insert( (-1 == leftAngle) ? 0 : ++leftAngle, prefix );
2346  }
2347  else {
2348  // toggle between "DecryptedMsg." and "DeCryptedMsg."
2349  // to avoid same message id
2350  QCharRef c = msgId[ oldIdx+2 ];
2351  if ( 'C' == c )
2352  c = 'c';
2353  else
2354  c = 'C';
2355  }
2356  newMsg->setMsgId( msgId );
2357  mMsgView->setIdOfLastViewedMessage( msgId );
2358  }
2359  // insert the unencrypted message
2360  kDebug() << "Adding unencrypted message to folder";
2361  mFolder->addMsg( newMsg );
2362  /* Figure out its index in the folder for selecting. This must be count()-1,
2363  * since we append. Be safe and do find, though, just in case. */
2364  int newMsgIdx = mFolder->find( newMsg );
2365  Q_ASSERT( newMsgIdx != -1 );
2366  /* we need this unget, to have the message displayed correctly initially */
2367  mFolder->unGetMsg( newMsgIdx );
2368  int idx = mFolder->find( oldMsg );
2369  Q_ASSERT( idx != -1 );
2370  /* only select here, so the old one is not un-Gotten before, which would
2371  * render the pointer we hold invalid so that find would fail */
2372 #if 0
2373  // FIXME (Pragma)
2374  mHeaders->setCurrentItemByIndex( newMsgIdx );
2375 #endif
2376  // remove the old one
2377  if ( idx != -1 ) {
2378  kDebug() << "Deleting encrypted message";
2379  mFolder->take( idx );
2380  }
2381 
2382  kDebug() << "Updating message actions";
2383  updateMessageActions();
2384 
2385  kDebug() << "Done.";
2386  } else
2387  kDebug() << "NO EXTRA UNENCRYPTED MESSAGE FOUND";
2388 #else
2389  kDebug() << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO;
2390 #endif
2391  } else
2392  kDebug() << "PANIC: NO OLD MESSAGE FOUND";
2393 }
2394 
2395 void KMMainWidget::slotFocusOnNextMessage()
2396 {
2397  mMessagePane->focusNextMessageItem(MessageList::Core::MessageTypeAny, true,false );
2398 }
2399 
2400 void KMMainWidget::slotFocusOnPrevMessage()
2401 {
2402  mMessagePane->focusPreviousMessageItem( MessageList::Core::MessageTypeAny, true, false );
2403 }
2404 
2405 void KMMainWidget::slotSelectFirstMessage()
2406 {
2407  mMessagePane->selectFirstMessageItem( MessageList::Core::MessageTypeAny, true );
2408 }
2409 
2410 void KMMainWidget::slotSelectLastMessage()
2411 {
2412  mMessagePane->selectLastMessageItem( MessageList::Core::MessageTypeAny, true );
2413 }
2414 
2415 void KMMainWidget::slotSelectFocusedMessage()
2416 {
2417  mMessagePane->selectFocusedMessageItem(true );
2418 }
2419 
2420 void KMMainWidget::slotSelectNextMessage()
2421 {
2422  mMessagePane->selectNextMessageItem( MessageList::Core::MessageTypeAny,
2423  MessageList::Core::ClearExistingSelection,
2424  true, false );
2425 }
2426 
2427 void KMMainWidget::slotExtendSelectionToNextMessage()
2428 {
2429  mMessagePane->selectNextMessageItem(
2430  MessageList::Core::MessageTypeAny,
2431  MessageList::Core::GrowOrShrinkExistingSelection,
2432  true, // center item
2433  false // don't loop in folder
2434  );
2435 }
2436 
2437 void KMMainWidget::slotSelectNextUnreadMessage()
2438 {
2439  // The looping logic is: "Don't loop" just never loops, "Loop in current folder"
2440  // loops just in current folder, "Loop in all folders" loops in the current folder
2441  // first and then after confirmation jumps to the next folder.
2442  // A bad point here is that if you answer "No, and don't ask me again" to the confirmation
2443  // dialog then you have "Loop in current folder" and "Loop in all folders" that do
2444  // the same thing and no way to get the old behaviour. However, after a consultation on #kontact,
2445  // for bug-to-bug backward compatibility, the masters decided to keep it b0rken :D
2446  // If nobody complains, it stays like it is: if you complain enough maybe the masters will
2447  // decide to reconsider :)
2448  if ( !mMessagePane->selectNextMessageItem(
2449  MessageList::Core::MessageTypeUnreadOnly,
2450  MessageList::Core::ClearExistingSelection,
2451  true, // center item
2452  /*GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInCurrentFolder*/
2453  GlobalSettings::self()->loopOnGotoUnread() != GlobalSettings::EnumLoopOnGotoUnread::DontLoop
2454  ) )
2455  {
2456  // no next unread message was found in the current folder
2457  if ( ( GlobalSettings::self()->loopOnGotoUnread() ==
2458  GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders ) ||
2459  ( GlobalSettings::self()->loopOnGotoUnread() ==
2460  GlobalSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders ) )
2461  {
2462  mGoToFirstUnreadMessageInSelectedFolder = true;
2463  mFolderTreeWidget->folderTreeView()->selectNextUnreadFolder( true );
2464  mGoToFirstUnreadMessageInSelectedFolder = false;
2465  }
2466  }
2467 }
2468 
2469 void KMMainWidget::slotSelectPreviousMessage()
2470 {
2471  mMessagePane->selectPreviousMessageItem( MessageList::Core::MessageTypeAny,
2472  MessageList::Core::ClearExistingSelection,
2473  true, false );
2474 }
2475 
2476 void KMMainWidget::slotExtendSelectionToPreviousMessage()
2477 {
2478  mMessagePane->selectPreviousMessageItem(
2479  MessageList::Core::MessageTypeAny,
2480  MessageList::Core::GrowOrShrinkExistingSelection,
2481  true, // center item
2482  false // don't loop in folder
2483  );
2484 }
2485 
2486 void KMMainWidget::slotSelectPreviousUnreadMessage()
2487 {
2488  if ( !mMessagePane->selectPreviousMessageItem(
2489  MessageList::Core::MessageTypeUnreadOnly,
2490  MessageList::Core::ClearExistingSelection,
2491  true, // center item
2492  GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInCurrentFolder
2493  ) )
2494  {
2495  // no next unread message was found in the current folder
2496  if ( ( GlobalSettings::self()->loopOnGotoUnread() ==
2497  GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders ) ||
2498  ( GlobalSettings::self()->loopOnGotoUnread() ==
2499  GlobalSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders ) )
2500  {
2501  mGoToFirstUnreadMessageInSelectedFolder = true;
2502  mFolderTreeWidget->folderTreeView()->selectPrevUnreadFolder();
2503  mGoToFirstUnreadMessageInSelectedFolder = false;
2504  }
2505  }
2506 }
2507 
2508 void KMMainWidget::slotDisplayCurrentMessage()
2509 {
2510  if ( mMessagePane->currentItem().isValid() && !mMessagePane->searchEditHasFocus() )
2511  slotMessageActivated( mMessagePane->currentItem() );
2512 }
2513 
2514 // Called by double-clicked or 'Enter' in the messagelist -> pop up reader window
2515 void KMMainWidget::slotMessageActivated( const Akonadi::Item &msg )
2516 {
2517  if ( !mCurrentFolder || !msg.isValid() )
2518  return;
2519 
2520  if ( CommonKernel->folderIsDraftOrOutbox( mCurrentFolder->collection() ) )
2521  {
2522  mMsgActions->setCurrentMessage( msg );
2523  mMsgActions->editCurrentMessage();
2524  return;
2525  }
2526 
2527  if ( CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) ) {
2528  slotUseTemplate();
2529  return;
2530  }
2531 
2532  // Try to fetch the mail, even in offline mode, it might be cached
2533  KMFetchMessageCommand *cmd = new KMFetchMessageCommand(this, msg);
2534  connect(cmd, SIGNAL(completed(KMCommand*)),
2535  this, SLOT(slotItemsFetchedForActivation(KMCommand*)));
2536  cmd->start();
2537 }
2538 
2539 void KMMainWidget::slotItemsFetchedForActivation( KMCommand *command )
2540 {
2541  KMCommand::Result result = command->result();
2542  if (result != KMCommand::OK) {
2543  kDebug() << "Result:" << result;
2544  return;
2545  }
2546 
2547  KMFetchMessageCommand *fetchCmd = qobject_cast<KMFetchMessageCommand*>(command);
2548  const Item msg = fetchCmd->item();
2549 
2550  KMReaderMainWin *win = new KMReaderMainWin( mFolderDisplayFormatPreference, mFolderHtmlLoadExtPreference );
2551  const bool useFixedFont = mMsgView ? mMsgView->isFixedFont() :
2552  MessageViewer::GlobalSettings::self()->useFixedFont();
2553  win->setUseFixedFont( useFixedFont );
2554 
2555 
2556  const Akonadi::Collection parentCollection = MailCommon::Util::parentCollectionFromItem(msg);
2557  win->showMessage( overrideEncoding(), msg, parentCollection );
2558  win->show();
2559 }
2560 
2561 void KMMainWidget::slotMessageStatusChangeRequest( const Akonadi::Item &item, const Akonadi::MessageStatus & set, const Akonadi::MessageStatus &clear )
2562 {
2563  if ( !item.isValid() )
2564  return;
2565 
2566  if ( clear.toQInt32() != Akonadi::MessageStatus().toQInt32() )
2567  {
2568  KMCommand *command = new KMSetStatusCommand( clear, Akonadi::Item::List() << item, true );
2569  command->start();
2570  }
2571 
2572  if ( set.toQInt32() != Akonadi::MessageStatus().toQInt32() )
2573  {
2574  KMCommand *command = new KMSetStatusCommand( set, Akonadi::Item::List() << item, false );
2575  command->start();
2576  }
2577 }
2578 
2579 //-----------------------------------------------------------------------------
2580 void KMMainWidget::slotMarkAll()
2581 {
2582  mMessagePane->selectAll();
2583  updateMessageActions();
2584 }
2585 
2586 void KMMainWidget::slotMessagePopup(const Akonadi::Item&msg ,const KUrl&aUrl,const KUrl &imageUrl,const QPoint& aPoint)
2587 {
2588  updateMessageMenu();
2589 
2590  const QString email = KPIMUtils::firstEmailAddress( aUrl.path() ).toLower();
2591  if ( aUrl.protocol() == QLatin1String("mailto") && !email.isEmpty()) {
2592  Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob( this );
2593  job->setLimit( 1 );
2594  job->setQuery( Akonadi::ContactSearchJob::Email, email, Akonadi::ContactSearchJob::ExactMatch );
2595  job->setProperty( "msg", QVariant::fromValue( msg ) );
2596  job->setProperty( "point", aPoint );
2597  job->setProperty( "imageUrl", imageUrl );
2598  job->setProperty( "url", aUrl );
2599  connect( job, SIGNAL(result(KJob*)), SLOT(slotContactSearchJobForMessagePopupDone(KJob*)) );
2600  } else {
2601  showMessagePopup(msg, aUrl, imageUrl, aPoint, false, false);
2602  }
2603 }
2604 
2605 void KMMainWidget::slotContactSearchJobForMessagePopupDone( KJob *job )
2606 {
2607  const Akonadi::ContactSearchJob *searchJob = qobject_cast<Akonadi::ContactSearchJob*>( job );
2608  const bool contactAlreadyExists = !searchJob->contacts().isEmpty();
2609 
2610  const QList<Akonadi::Item> listContact = searchJob->items();
2611  const bool uniqueContactFound = (listContact.count() == 1);
2612  if (uniqueContactFound) {
2613  mMsgView->setContactItem(listContact.first(), searchJob->contacts().at(0));
2614  } else {
2615  mMsgView->clearContactItem();
2616  }
2617  const Akonadi::Item msg = job->property( "msg" ).value<Akonadi::Item>();
2618  const QPoint aPoint = job->property( "point" ).toPoint();
2619  const KUrl imageUrl = job->property("imageUrl").value<KUrl>();
2620  const KUrl url = job->property( "url" ).value<KUrl>();
2621 
2622  showMessagePopup(msg, url, imageUrl, aPoint, contactAlreadyExists, uniqueContactFound);
2623 }
2624 
2625 void KMMainWidget::showMessagePopup(const Akonadi::Item&msg ,const KUrl&url,const KUrl &imageUrl,const QPoint& aPoint, bool contactAlreadyExists, bool uniqueContactFound)
2626 {
2627  KMenu *menu = new KMenu;
2628 
2629  bool urlMenuAdded = false;
2630 
2631  if ( !url.isEmpty() ) {
2632  if ( url.protocol() == QLatin1String( "mailto" ) ) {
2633  // popup on a mailto URL
2634  menu->addAction( mMsgView->mailToComposeAction() );
2635  menu->addAction( mMsgView->mailToReplyAction() );
2636  menu->addAction( mMsgView->mailToForwardAction() );
2637 
2638  menu->addSeparator();
2639 
2640  if ( contactAlreadyExists ) {
2641  if (uniqueContactFound) {
2642  menu->addAction( mMsgView->editContactAction() );
2643  } else {
2644  menu->addAction( mMsgView->openAddrBookAction() );
2645  }
2646  } else {
2647  menu->addAction( mMsgView->addAddrBookAction() );
2648  menu->addAction( mMsgView->addToExistingContactAction() );
2649  }
2650  menu->addSeparator();
2651  menu->addMenu(mMsgView->viewHtmlOption());
2652  menu->addSeparator();
2653  menu->addAction( mMsgView->copyURLAction() );
2654  urlMenuAdded = true;
2655  } else if ( url.protocol() != QLatin1String( "attachment" ) ) {
2656  // popup on a not-mailto URL
2657  menu->addAction( mMsgView->urlOpenAction() );
2658  menu->addAction( mMsgView->addBookmarksAction() );
2659  menu->addAction( mMsgView->urlSaveAsAction() );
2660  menu->addAction( mMsgView->copyURLAction() );
2661  if (mMsgView->isAShortUrl(url)) {
2662  menu->addSeparator();
2663  menu->addAction( mMsgView->expandShortUrlAction() );
2664  }
2665  if (!imageUrl.isEmpty()) {
2666  menu->addSeparator();
2667  menu->addAction( mMsgView->copyImageLocation());
2668  menu->addAction( mMsgView->downloadImageToDiskAction());
2669  menu->addAction( mMsgView->shareImage());
2670  if (mMsgView->adblockEnabled()) {
2671  menu->addSeparator();
2672  menu->addAction( mMsgView->blockImage());
2673  }
2674  }
2675  urlMenuAdded = true;
2676  }
2677  kDebug() << "URL is:" << url;
2678  }
2679  const QString selectedText = mMsgView ? mMsgView->copyText() : QString();
2680  if ( mMsgView && !selectedText.isEmpty() ) {
2681  if ( urlMenuAdded ) {
2682  menu->addSeparator();
2683  }
2684  menu->addAction( mMsgActions->replyMenu() );
2685  menu->addSeparator();
2686 
2687  menu->addAction( mMsgView->copyAction() );
2688  menu->addAction( mMsgView->selectAllAction() );
2689  menu->addSeparator();
2690  mMsgActions->addWebShortcutsMenu(menu,selectedText);
2691  menu->addSeparator();
2692  menu->addAction(mMsgView->translateAction());
2693  menu->addSeparator();
2694  menu->addAction( mMsgView->speakTextAction());
2695  } else if ( !urlMenuAdded ) {
2696  // popup somewhere else (i.e., not a URL) on the message
2697  if (!mMessagePane->currentMessage()) {
2698  // no messages
2699  delete menu;
2700  return;
2701  }
2702  Akonadi::Collection parentCol = msg.parentCollection();
2703  if ( parentCol.isValid() && CommonKernel->folderIsTemplates( parentCol) ) {
2704  menu->addAction( mUseAction );
2705  } else {
2706  menu->addAction( mMsgActions->replyMenu() );
2707  menu->addAction( mMsgActions->forwardMenu() );
2708  }
2709  if ( parentCol.isValid() && CommonKernel->folderIsSentMailFolder( parentCol ) ) {
2710  menu->addAction( sendAgainAction() );
2711  } else {
2712  menu->addAction( editAction() );
2713  }
2714  menu->addAction( mailingListActionMenu() );
2715  menu->addSeparator();
2716 
2717  menu->addAction( mCopyActionMenu );
2718  menu->addAction( mMoveActionMenu );
2719 
2720  menu->addSeparator();
2721 
2722  menu->addAction( mMsgActions->messageStatusMenu() );
2723  menu->addSeparator();
2724  if ( mMsgView ) {
2725  if (!imageUrl.isEmpty()) {
2726  menu->addSeparator();
2727  menu->addAction( mMsgView->copyImageLocation());
2728  menu->addAction( mMsgView->downloadImageToDiskAction());
2729  menu->addAction( mMsgView->shareImage());
2730  menu->addSeparator();
2731  if (mMsgView->adblockEnabled()) {
2732  menu->addAction( mMsgView->blockImage() );
2733  menu->addSeparator();
2734  }
2735  }
2736  menu->addAction( mMsgView->viewSourceAction() );
2737  menu->addAction( mMsgView->toggleFixFontAction() );
2738  menu->addAction( mMsgView->toggleMimePartTreeAction() );
2739  }
2740  menu->addSeparator();
2741  if (mMsgActions->printPreviewAction())
2742  menu->addAction( mMsgActions->printPreviewAction() );
2743  menu->addAction( mMsgActions->printAction() );
2744  menu->addAction( mSaveAsAction );
2745  menu->addAction( mSaveAttachmentsAction );
2746  menu->addSeparator();
2747  if ( parentCol.isValid() && CommonKernel->folderIsTrash(parentCol) ) {
2748  menu->addAction( mDeleteAction );
2749  } else {
2750  menu->addAction( akonadiStandardAction( Akonadi::StandardMailActionManager::MoveToTrash ) );
2751  }
2752  menu->addSeparator();
2753  menu->addAction( mMsgView->createTodoAction() );
2754  menu->addAction( mMsgView->createEventAction() );
2755  menu->addSeparator();
2756  if (mMsgView) {
2757  menu->addAction( mMsgView->saveMessageDisplayFormatAction() );
2758  menu->addAction( mMsgView->resetMessageDisplayFormatAction() );
2759  menu->addSeparator();
2760  }
2761  menu->addAction( mMsgActions->annotateAction() );
2762  if (mMsgView && mMsgView->adblockEnabled()) {
2763  menu->addSeparator();
2764  menu->addAction( mMsgView->openBlockableItems());
2765  }
2766  menu->addSeparator();
2767  menu->addAction( mMsgActions->addFollowupReminderAction() );
2768  if (kmkernel->allowToDebugBalooSupport()) {
2769  menu->addSeparator();
2770  menu->addAction( mMsgActions->debugBalooAction() );
2771  }
2772  }
2773  KAcceleratorManager::manage(menu);
2774  menu->exec( aPoint, 0 );
2775  delete menu;
2776 }
2777 
2778 //-----------------------------------------------------------------------------
2779 void KMMainWidget::setupActions()
2780 {
2781  mMsgActions = new KMail::MessageActions( actionCollection(), this );
2782  mMsgActions->setMessageView( mMsgView );
2783 
2784  //----- File Menu
2785  mSaveAsAction = new KAction(KIcon(QLatin1String("document-save")), i18n("Save &As..."), this);
2786  actionCollection()->addAction(QLatin1String("file_save_as"), mSaveAsAction );
2787  connect(mSaveAsAction, SIGNAL(triggered(bool)), SLOT(slotSaveMsg()));
2788  mSaveAsAction->setShortcut(KStandardShortcut::save());
2789 
2790  mOpenAction = KStandardAction::open( this, SLOT(slotOpenMsg()),
2791  actionCollection() );
2792 
2793  mOpenRecentAction = KStandardAction::openRecent( this, SLOT(slotOpenRecentMsg(KUrl)),
2794  actionCollection() );
2795  KConfigGroup grp = mConfig->group(QLatin1String("Recent Files"));
2796  mOpenRecentAction->loadEntries(grp);
2797 
2798  {
2799  KAction *action = new KAction(i18n("&Expire All Folders"), this);
2800  actionCollection()->addAction(QLatin1String("expire_all_folders"), action );
2801  connect(action, SIGNAL(triggered(bool)), SLOT(slotExpireAll()));
2802  }
2803  {
2804  KAction *action = new KAction(KIcon(QLatin1String("mail-receive")), i18n("Check &Mail"), this);
2805  actionCollection()->addAction(QLatin1String("check_mail"), action );
2806  connect(action, SIGNAL(triggered(bool)), SLOT(slotCheckMail()));
2807  action->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_L));
2808  }
2809 
2810  KActionMenuAccount *actActionMenu = new KActionMenuAccount(this);
2811  actActionMenu->setIcon(KIcon(QLatin1String("mail-receive")));
2812  actActionMenu->setText(i18n("Check Mail In"));
2813  actActionMenu->setIconText( i18n("Check Mail") );
2814  actActionMenu->setToolTip( i18n("Check Mail") );
2815 
2816  actionCollection()->addAction(QLatin1String("check_mail_in"), actActionMenu );
2817  connect(actActionMenu, SIGNAL(triggered(bool)), this, SLOT(slotCheckMail()));
2818 
2819  mSendQueued = new KAction(KIcon(QLatin1String("mail-send")), i18n("&Send Queued Messages"), this);
2820  actionCollection()->addAction(QLatin1String("send_queued"), mSendQueued );
2821  connect(mSendQueued, SIGNAL(triggered(bool)), SLOT(slotSendQueued()));
2822  {
2823 
2824  KAction * action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::ToggleWorkOffline );
2825  mAkonadiStandardActionManager->interceptAction( Akonadi::StandardActionManager::ToggleWorkOffline );
2826  action->setCheckable(false);
2827  connect( action, SIGNAL(triggered(bool)), this, SLOT(slotOnlineStatus()) );
2828  action->setText( i18n("Online status (unknown)") );
2829  }
2830 
2831  mSendActionMenu = new KActionMenuTransport(this);
2832  mSendActionMenu->setIcon(KIcon(QLatin1String("mail-send-via")));
2833  mSendActionMenu->setText(i18n("Send Queued Messages Via"));
2834  actionCollection()->addAction(QLatin1String("send_queued_via"), mSendActionMenu );
2835 
2836  connect(mSendActionMenu, SIGNAL(transportSelected(MailTransport::Transport*)), SLOT(slotSendQueuedVia(MailTransport::Transport*)));
2837 
2838  //----- Tools menu
2839  if (parent()->inherits("KMMainWin")) {
2840  KAction *action = new KAction(KIcon(QLatin1String("x-office-address-book")), i18n("&Address Book"), this);
2841  actionCollection()->addAction(QLatin1String("addressbook"), action );
2842  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotAddrBook()));
2843  if (KStandardDirs::findExe(QLatin1String("kaddressbook")).isEmpty())
2844  action->setEnabled(false);
2845  }
2846 
2847  {
2848  KAction *action = new KAction(KIcon(QLatin1String("pgp-keys")), i18n("Certificate Manager"), this);
2849  actionCollection()->addAction(QLatin1String("tools_start_certman"), action );
2850  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotStartCertManager()));
2851  // disable action if no certman binary is around
2852  if (KStandardDirs::findExe(QLatin1String("kleopatra")).isEmpty())
2853  action->setEnabled(false);
2854  }
2855  {
2856  KAction *action = new KAction(KIcon(QLatin1String("pgp-keys")), i18n("GnuPG Log Viewer"), this);
2857  actionCollection()->addAction(QLatin1String("tools_start_kwatchgnupg"), action );
2858  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotStartWatchGnuPG()));
2859 #ifdef Q_OS_WIN32
2860  // not ported yet, underlying infrastructure missing on Windows
2861  const bool usableKWatchGnupg = false;
2862 #else
2863  // disable action if no kwatchgnupg binary is around
2864  bool usableKWatchGnupg = !KStandardDirs::findExe(QLatin1String("kwatchgnupg")).isEmpty();
2865 #endif
2866  action->setEnabled(usableKWatchGnupg);
2867  }
2868  {
2869  KAction *action = new KAction(KIcon(QLatin1String("document-import")), i18n("&Import Messages..."), this);
2870  actionCollection()->addAction(QLatin1String("import"), action );
2871  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotImport()));
2872  if (KStandardDirs::findExe(QLatin1String("kmailcvt")).isEmpty()) action->setEnabled(false);
2873  }
2874 
2875 #if !defined(NDEBUG)
2876  {
2877  KAction *action = new KAction(i18n("&Debug Sieve..."), this);
2878  actionCollection()->addAction(QLatin1String("tools_debug_sieve"), action );
2879  connect(action, SIGNAL(triggered(bool)), SLOT(slotDebugSieve()));
2880  }
2881 #endif
2882 
2883  {
2884  KAction *action = new KAction(i18n("Filter &Log Viewer..."), this);
2885  actionCollection()->addAction(QLatin1String("filter_log_viewer"), action );
2886  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotFilterLogViewer()));
2887  }
2888  {
2889  KAction *action = new KAction(i18n("&Anti-Spam Wizard..."), this);
2890  actionCollection()->addAction(QLatin1String("antiSpamWizard"), action );
2891  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotAntiSpamWizard()));
2892  }
2893  {
2894  KAction *action = new KAction(i18n("&Anti-Virus Wizard..."), this);
2895  actionCollection()->addAction(QLatin1String("antiVirusWizard"), action );
2896  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotAntiVirusWizard()));
2897  }
2898  {
2899  KAction *action = new KAction( i18n("&Account Wizard..."), this );
2900  actionCollection()->addAction( QLatin1String("accountWizard"), action );
2901  connect( action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotAccountWizard()) );
2902  }
2903  {
2904  KAction *action = new KAction( i18n("&Import Wizard..."), this );
2905  actionCollection()->addAction( QLatin1String("importWizard"), action );
2906  connect( action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotImportWizard()) );
2907  }
2908  if ( KSieveUi::Util::allowOutOfOfficeSettings() )
2909  {
2910  KAction *action = new KAction( i18n("Edit \"Out of Office\" Replies..."), this );
2911  actionCollection()->addAction( QLatin1String("tools_edit_vacation"), action );
2912  connect( action, SIGNAL(triggered(bool)), SLOT(slotEditVacation()) );
2913  }
2914 
2915  {
2916  KAction *action = new KAction(i18n("&Configure Automatic Archiving..."), this);
2917  actionCollection()->addAction(QLatin1String("tools_automatic_archiving"), action );
2918  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotConfigureAutomaticArchiving()));
2919  }
2920 
2921  {
2922  KAction *action = new KAction(i18n("Delayed Messages..."), this);
2923  actionCollection()->addAction(QLatin1String("message_delayed"), action );
2924  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotConfigureSendLater()));
2925  }
2926 
2927  {
2928  KAction *action = new KAction(i18n("Followup Reminder Messages..."), this);
2929  actionCollection()->addAction(QLatin1String("followup_reminder_messages"), action );
2930  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotConfigureFollowupReminder()));
2931  }
2932 
2933 
2934  // Disable the standard action delete key sortcut.
2935  KAction* const standardDelAction = akonadiStandardAction( Akonadi::StandardActionManager::DeleteItems );
2936  standardDelAction->setShortcut( QKeySequence() );
2937 
2938  //----- Edit Menu
2939 
2940  /* The delete action is nowhere in the gui, by default, so we need to make
2941  * sure it is plugged into the KAccel now, since that won't happen on
2942  * XMLGui construction or manual ->plug(). This is only a problem when run
2943  * as a part, though. */
2944  mDeleteAction = new KAction(KIcon(QLatin1String("edit-delete")), i18nc("@action Hard delete, bypassing trash", "&Delete"), this);
2945  actionCollection()->addAction(QLatin1String("delete"), mDeleteAction );
2946  connect(mDeleteAction, SIGNAL(triggered(bool)), SLOT(slotDeleteMsg()));
2947  mDeleteAction->setShortcut(QKeySequence(Qt::SHIFT+Qt::Key_Delete));
2948 
2949  mTrashThreadAction = new KAction(i18n("M&ove Thread to Trash"), this);
2950  actionCollection()->addAction(QLatin1String("move_thread_to_trash"), mTrashThreadAction );
2951  mTrashThreadAction->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Delete));
2952  mTrashThreadAction->setIcon(KIcon(QLatin1String("user-trash")));
2953  mTrashThreadAction->setHelpText(i18n("Move thread to trashcan") );
2954  connect(mTrashThreadAction, SIGNAL(triggered(bool)), SLOT(slotTrashThread()));
2955 
2956  mDeleteThreadAction = new KAction(KIcon(QLatin1String("edit-delete")), i18n("Delete T&hread"), this);
2957  actionCollection()->addAction(QLatin1String("delete_thread"), mDeleteThreadAction );
2958  connect(mDeleteThreadAction, SIGNAL(triggered(bool)), SLOT(slotDeleteThread()));
2959  mDeleteThreadAction->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_Delete));
2960 
2961  mSearchMessages = new KAction(KIcon(QLatin1String("edit-find-mail")), i18n("&Find Messages..."), this);
2962  actionCollection()->addAction(QLatin1String("search_messages"), mSearchMessages );
2963  connect(mSearchMessages, SIGNAL(triggered(bool)), SLOT(slotRequestFullSearchFromQuickSearch()));
2964  mSearchMessages->setShortcut(QKeySequence(Qt::Key_S));
2965 
2966  {
2967  KAction *action = new KAction(i18n("Select &All Messages"), this);
2968  actionCollection()->addAction(QLatin1String("mark_all_messages"), action );
2969  connect(action, SIGNAL(triggered(bool)), SLOT(slotMarkAll()));
2970  action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_A ) );
2971  }
2972 
2973  //----- Folder Menu
2974 
2975  mFolderMailingListPropertiesAction = new KAction(i18n("&Mailing List Management..."), this);
2976  actionCollection()->addAction(QLatin1String("folder_mailinglist_properties"), mFolderMailingListPropertiesAction );
2977  connect(mFolderMailingListPropertiesAction, SIGNAL(triggered(bool)), mManageShowCollectionProperties, SLOT(slotFolderMailingListProperties()));
2978  // mFolderMailingListPropertiesAction->setIcon(KIcon("document-properties-mailing-list"));
2979 
2980  mShowFolderShortcutDialogAction = new KAction(KIcon(QLatin1String("configure-shortcuts")), i18n("&Assign Shortcut..."), this);
2981  actionCollection()->addAction(QLatin1String("folder_shortcut_command"), mShowFolderShortcutDialogAction );
2982  connect( mShowFolderShortcutDialogAction, SIGNAL(triggered(bool)), mManageShowCollectionProperties,
2983  SLOT(slotShowFolderShortcutDialog()) );
2984 
2985  // FIXME: this action is not currently enabled in the rc file, but even if
2986  // it were there is inconsistency between the action name and action.
2987  // "Expiration Settings" implies that this will lead to a settings dialogue
2988  // and it should be followed by a "...", but slotExpireFolder() performs
2989  // an immediate expiry.
2990  //
2991  // TODO: expire action should be disabled if there is no content or if
2992  // the folder can't delete messages.
2993  //
2994  // Leaving the action here for the moment, it and the "Expire" option in the
2995  // folder popup menu should be combined or at least made consistent. Same for
2996  // slotExpireFolder() and FolderViewItem::slotShowExpiryProperties().
2997  mExpireFolderAction = new KAction(i18n("&Expiration Settings"), this);
2998  actionCollection()->addAction(QLatin1String("expire"), mExpireFolderAction );
2999  connect(mExpireFolderAction, SIGNAL(triggered(bool)), this, SLOT(slotExpireFolder()));
3000 
3001 
3002  mAkonadiStandardActionManager->interceptAction( Akonadi::StandardMailActionManager::MoveToTrash );
3003  connect( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveToTrash ), SIGNAL(triggered(bool)), this, SLOT(slotTrashSelectedMessages()) );
3004 
3005 
3006  mAkonadiStandardActionManager->interceptAction( Akonadi::StandardMailActionManager::MoveAllToTrash );
3007  connect( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash ), SIGNAL(triggered(bool)), this, SLOT(slotEmptyFolder()) );
3008 
3009  mAkonadiStandardActionManager->interceptAction( Akonadi::StandardActionManager::DeleteCollections );
3010  connect( mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::DeleteCollections ), SIGNAL(triggered(bool)), this, SLOT(slotRemoveFolder()) );
3011 
3012  // ### PORT ME: Add this to the context menu. Not possible right now because
3013  // the context menu uses XMLGUI, and that would add the entry to
3014  // all collection context menus
3015  mArchiveFolderAction = new KAction( i18n( "&Archive Folder..." ), this );
3016  actionCollection()->addAction( QLatin1String("archive_folder"), mArchiveFolderAction );
3017  connect( mArchiveFolderAction, SIGNAL(triggered(bool)), SLOT(slotArchiveFolder()) );
3018 
3019  mDisplayMessageFormatMenu = new DisplayMessageFormatActionMenu(this);
3020  connect(mDisplayMessageFormatMenu, SIGNAL(changeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage)), this, SLOT(slotChangeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage)));
3021  actionCollection()->addAction(QLatin1String("display_format_message"), mDisplayMessageFormatMenu );
3022 
3023 
3024  mPreferHtmlLoadExtAction = new KToggleAction(i18n("Load E&xternal References"), this);
3025  actionCollection()->addAction(QLatin1String("prefer_html_external_refs"), mPreferHtmlLoadExtAction );
3026  connect(mPreferHtmlLoadExtAction, SIGNAL(triggered(bool)), SLOT(slotOverrideHtmlLoadExt()));
3027 
3028  {
3029  KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyCollections);
3030  action->setShortcut(QKeySequence(Qt::SHIFT+Qt::CTRL+Qt::Key_C));
3031  }
3032  {
3033  KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::Paste);
3034  action->setShortcut(QKeySequence(Qt::SHIFT+Qt::CTRL+Qt::Key_V));
3035  }
3036  {
3037  KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyItems);
3038  action->setShortcut(QKeySequence(Qt::ALT+Qt::CTRL+Qt::Key_C));
3039  }
3040  {
3041  KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CutItems );
3042  action->setShortcut(QKeySequence(Qt::ALT+Qt::CTRL+Qt::Key_X));
3043  }
3044 
3045  {
3046  KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyItemToMenu );
3047  action->setText(i18n("Copy Message To...") );
3048  action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::MoveItemToMenu );
3049  action->setText(i18n("Move Message To...") );
3050  }
3051 
3052  //----- Message Menu
3053  {
3054  KAction *action = new KAction(KIcon(QLatin1String("mail-message-new")), i18n("&New Message..."), this);
3055  actionCollection()->addAction(QLatin1String("new_message"), action );
3056  action->setIconText( i18nc("@action:intoolbar New Empty Message", "New" ) );
3057  connect(action, SIGNAL(triggered(bool)), SLOT(slotCompose()));
3058  // do not set a New shortcut if kmail is a component
3059  if ( !kmkernel->xmlGuiInstance().isValid() ) {
3060  action->setShortcut(KStandardShortcut::openNew());
3061  }
3062  }
3063 
3064  mTemplateMenu = new KActionMenu( KIcon( QLatin1String("document-new") ), i18n("Message From &Template"),
3065  actionCollection() );
3066  mTemplateMenu->setDelayed( true );
3067  actionCollection()->addAction(QLatin1String("new_from_template"), mTemplateMenu );
3068  connect( mTemplateMenu->menu(), SIGNAL(aboutToShow()), this,
3069  SLOT(slotShowNewFromTemplate()) );
3070  connect( mTemplateMenu->menu(), SIGNAL(triggered(QAction*)), this,
3071  SLOT(slotNewFromTemplate(QAction*)) );
3072 
3073  mMessageNewList = new KAction( KIcon( QLatin1String("mail-message-new-list") ),
3074  i18n( "New Message t&o Mailing-List..." ),
3075  this );
3076  actionCollection()->addAction(QLatin1String("post_message"), mMessageNewList);
3077  connect( mMessageNewList, SIGNAL(triggered(bool)),
3078  SLOT(slotPostToML()) );
3079  mMessageNewList->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_N ) );
3080 
3081  mSendAgainAction = new KAction(i18n("Send A&gain..."), this);
3082  actionCollection()->addAction(QLatin1String("send_again"), mSendAgainAction );
3083  connect(mSendAgainAction, SIGNAL(triggered(bool)), SLOT(slotResendMsg()));
3084 
3085  //----- Create filter actions
3086  mFilterMenu = new KActionMenu(KIcon(QLatin1String("view-filter")), i18n("&Create Filter"), this);
3087  actionCollection()->addAction(QLatin1String("create_filter"), mFilterMenu );
3088  connect( mFilterMenu, SIGNAL(triggered(bool)), this,
3089  SLOT(slotFilter()) );
3090  {
3091  KAction *action = new KAction(i18n("Filter on &Subject..."), this);
3092  actionCollection()->addAction(QLatin1String("subject_filter"), action );
3093  connect(action, SIGNAL(triggered(bool)), SLOT(slotSubjectFilter()));
3094  mFilterMenu->addAction( action );
3095  }
3096 
3097  {
3098  KAction *action = new KAction(i18n("Filter on &From..."), this);
3099  actionCollection()->addAction(QLatin1String("from_filter"), action );
3100  connect(action, SIGNAL(triggered(bool)), SLOT(slotFromFilter()));
3101  mFilterMenu->addAction( action );
3102  }
3103  {
3104  KAction *action = new KAction(i18n("Filter on &To..."), this);
3105  actionCollection()->addAction(QLatin1String("to_filter"), action );
3106  connect(action, SIGNAL(triggered(bool)), SLOT(slotToFilter()));
3107  mFilterMenu->addAction( action );
3108  }
3109  mFilterMenu->addAction( mMsgActions->listFilterAction() );
3110 
3111  mUseAction = new KAction( KIcon(QLatin1String("document-new")), i18n("New Message From &Template"), this );
3112  actionCollection()->addAction(QLatin1String("use_template"), mUseAction);
3113  connect(mUseAction, SIGNAL(triggered(bool)), SLOT(slotUseTemplate()));
3114  mUseAction->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_N));
3115 
3116  //----- "Mark Thread" submenu
3117  mThreadStatusMenu = new KActionMenu(i18n("Mark &Thread"), this);
3118  actionCollection()->addAction(QLatin1String("thread_status"), mThreadStatusMenu );
3119 
3120  mMarkThreadAsReadAction = new KAction(KIcon(QLatin1String("mail-mark-read")), i18n("Mark Thread as &Read"), this);
3121  actionCollection()->addAction(QLatin1String("thread_read"), mMarkThreadAsReadAction );
3122  connect(mMarkThreadAsReadAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusRead()));
3123  mMarkThreadAsReadAction->setHelpText(i18n("Mark all messages in the selected thread as read"));
3124  mThreadStatusMenu->addAction( mMarkThreadAsReadAction );
3125 
3126  mMarkThreadAsUnreadAction = new KAction(KIcon(QLatin1String("mail-mark-unread")), i18n("Mark Thread as &Unread"), this);
3127  actionCollection()->addAction(QLatin1String("thread_unread"), mMarkThreadAsUnreadAction );
3128  connect(mMarkThreadAsUnreadAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusUnread()));
3129  mMarkThreadAsUnreadAction->setHelpText(i18n("Mark all messages in the selected thread as unread"));
3130  mThreadStatusMenu->addAction( mMarkThreadAsUnreadAction );
3131 
3132  mThreadStatusMenu->addSeparator();
3133 
3134  //----- "Mark Thread" toggle actions
3135  mToggleThreadImportantAction = new KToggleAction(KIcon(QLatin1String("mail-mark-important")), i18n("Mark Thread as &Important"), this);
3136  actionCollection()->addAction(QLatin1String("thread_flag"), mToggleThreadImportantAction );
3137  connect(mToggleThreadImportantAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusImportant()));
3138  mToggleThreadImportantAction->setCheckedState( KGuiItem(i18n("Remove &Important Thread Mark")) );
3139  mThreadStatusMenu->addAction( mToggleThreadImportantAction );
3140 
3141  mToggleThreadToActAction = new KToggleAction(KIcon(QLatin1String("mail-mark-task")), i18n("Mark Thread as &Action Item"), this);
3142  actionCollection()->addAction(QLatin1String("thread_toact"), mToggleThreadToActAction );
3143  connect(mToggleThreadToActAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusToAct()));
3144  mToggleThreadToActAction->setCheckedState( KGuiItem(i18n("Remove &Action Item Thread Mark")) );
3145  mThreadStatusMenu->addAction( mToggleThreadToActAction );
3146 
3147  //------- "Watch and ignore thread" actions
3148  mWatchThreadAction = new KToggleAction(KIcon(QLatin1String("mail-thread-watch")), i18n("&Watch Thread"), this);
3149  actionCollection()->addAction(QLatin1String("thread_watched"), mWatchThreadAction );
3150  connect(mWatchThreadAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusWatched()));
3151 
3152  mIgnoreThreadAction = new KToggleAction(KIcon(QLatin1String("mail-thread-ignored")), i18n("&Ignore Thread"), this);
3153  actionCollection()->addAction(QLatin1String("thread_ignored"), mIgnoreThreadAction );
3154  connect(mIgnoreThreadAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusIgnored()));
3155 
3156  mThreadStatusMenu->addSeparator();
3157  mThreadStatusMenu->addAction( mWatchThreadAction );
3158  mThreadStatusMenu->addAction( mIgnoreThreadAction );
3159 
3160  mSaveAttachmentsAction = new KAction(KIcon(QLatin1String("mail-attachment")), i18n("Save A&ttachments..."), this);
3161  actionCollection()->addAction(QLatin1String("file_save_attachments"), mSaveAttachmentsAction );
3162  connect(mSaveAttachmentsAction, SIGNAL(triggered(bool)), SLOT(slotSaveAttachments()));
3163 
3164  mMoveActionMenu = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::MoveItemToMenu);
3165 
3166  mCopyActionMenu = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyItemToMenu);
3167 
3168  mApplyAllFiltersAction =
3169  new KAction( KIcon( QLatin1String("view-filter") ), i18n( "Appl&y All Filters" ), this );
3170  actionCollection()->addAction( QLatin1String("apply_filters"), mApplyAllFiltersAction );
3171  connect( mApplyAllFiltersAction, SIGNAL(triggered(bool)),
3172  SLOT(slotApplyFilters()) );
3173  mApplyAllFiltersAction->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_J ) );
3174 
3175  mApplyFilterActionsMenu = new KActionMenu( i18n( "A&pply Filter" ), this );
3176  actionCollection()->addAction( QLatin1String("apply_filter_actions"), mApplyFilterActionsMenu );
3177 
3178  {
3179  KAction *action = new KAction(i18nc("View->","&Expand Thread / Group"), this);
3180  actionCollection()->addAction(QLatin1String("expand_thread"), action );
3181  action->setShortcut(QKeySequence(Qt::Key_Period));
3182  action->setHelpText(i18n("Expand the current thread or group"));
3183  connect(action, SIGNAL(triggered(bool)), SLOT(slotExpandThread()));
3184  }
3185  {
3186  KAction *action = new KAction(i18nc("View->","&Collapse Thread / Group"), this);
3187  actionCollection()->addAction(QLatin1String("collapse_thread"), action );
3188  action->setShortcut(QKeySequence(Qt::Key_Comma));
3189  action->setHelpText( i18n("Collapse the current thread or group"));
3190  connect(action, SIGNAL(triggered(bool)), SLOT(slotCollapseThread()));
3191  }
3192  {
3193  KAction *action = new KAction(i18nc("View->","Ex&pand All Threads"), this);
3194  actionCollection()->addAction(QLatin1String("expand_all_threads"), action );
3195  action->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Period));
3196  action->setHelpText( i18n("Expand all threads in the current folder"));
3197  connect(action, SIGNAL(triggered(bool)), SLOT(slotExpandAllThreads()));
3198  }
3199  {
3200  KAction *action = new KAction(i18nc("View->","C&ollapse All Threads"), this);
3201  actionCollection()->addAction(QLatin1String("collapse_all_threads"), action );
3202  action->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Comma));
3203  action->setHelpText( i18n("Collapse all threads in the current folder"));
3204  connect(action, SIGNAL(triggered(bool)), SLOT(slotCollapseAllThreads()));
3205  }
3206 
3207 
3208  KAction *dukeOfMonmoth = new KAction(i18n("&Display Message"), this);
3209  actionCollection()->addAction(QLatin1String("display_message"), dukeOfMonmoth );
3210  connect(dukeOfMonmoth, SIGNAL(triggered(bool)), SLOT(slotDisplayCurrentMessage()));
3211  KShortcut shortcut = KShortcut(QKeySequence( Qt::Key_Enter ));
3212  shortcut.setAlternate( QKeySequence( Qt::Key_Return ) );
3213  dukeOfMonmoth->setShortcuts( shortcut );
3214 
3215  //----- Go Menu
3216  {
3217  KAction *action = new KAction(i18n("&Next Message"), this);
3218  actionCollection()->addAction(QLatin1String("go_next_message"), action );
3219  action->setShortcuts(KShortcut( QLatin1String("N; Right") ));
3220  action->setHelpText(i18n("Go to the next message"));
3221  connect(action, SIGNAL(triggered(bool)), SLOT(slotSelectNextMessage()));
3222  }
3223  {
3224  KAction *action = new KAction(i18n("Next &Unread Message"), this);
3225  actionCollection()->addAction(QLatin1String("go_next_unread_message"), action );
3226  action->setShortcut(QKeySequence(Qt::Key_Plus));
3227  if ( QApplication::isRightToLeft() ) {
3228  action->setIcon( KIcon( QLatin1String("go-previous") ) );
3229  } else {
3230  action->setIcon( KIcon( QLatin1String("go-next") ) );
3231  }
3232  action->setIconText( i18nc( "@action:inmenu Goto next unread message", "Next" ) );
3233  action->setHelpText(i18n("Go to the next unread message"));
3234  connect(action, SIGNAL(triggered(bool)), SLOT(slotSelectNextUnreadMessage()));
3235  }
3236  {
3237  KAction *action = new KAction(i18n("&Previous Message"), this);
3238  actionCollection()->addAction(QLatin1String("go_prev_message"), action );
3239  action->setHelpText(i18n("Go to the previous message"));
3240  action->setShortcuts(KShortcut( QLatin1String("P; Left") ));
3241  connect(action, SIGNAL(triggered(bool)), SLOT(slotSelectPreviousMessage()));
3242  }
3243  {
3244  KAction *action = new KAction(i18n("Previous Unread &Message"), this);
3245  actionCollection()->addAction(QLatin1String("go_prev_unread_message"), action );
3246  action->setShortcut(QKeySequence(Qt::Key_Minus));
3247  if ( QApplication::isRightToLeft() ) {
3248  action->setIcon( KIcon( QLatin1String("go-next") ) );
3249  } else {
3250  action->setIcon( KIcon( QLatin1String("go-previous") ) );
3251  }
3252  action->setIconText( i18nc( "@action:inmenu Goto previous unread message.","Previous" ) );
3253  action->setHelpText(i18n("Go to the previous unread message"));
3254  connect(action, SIGNAL(triggered(bool)), SLOT(slotSelectPreviousUnreadMessage()));
3255  }
3256  {
3257  KAction *action = new KAction(i18n("Next Unread &Folder"), this);
3258  actionCollection()->addAction(QLatin1String("go_next_unread_folder"), action );
3259  connect(action, SIGNAL(triggered(bool)), SLOT(slotNextUnreadFolder()));
3260  action->setShortcut(QKeySequence(Qt::ALT+Qt::Key_Plus));
3261  action->setHelpText(i18n("Go to the next folder with unread messages"));
3262  }
3263  {
3264  KAction *action = new KAction(i18n("Previous Unread F&older"), this);
3265  actionCollection()->addAction(QLatin1String("go_prev_unread_folder"), action );
3266  action->setShortcut(QKeySequence(Qt::ALT+Qt::Key_Minus));
3267  action->setHelpText(i18n("Go to the previous folder with unread messages"));
3268  connect(action, SIGNAL(triggered(bool)), SLOT(slotPrevUnreadFolder()));
3269  }
3270  {
3271  KAction *action = new KAction(i18nc("Go->","Next Unread &Text"), this);
3272  actionCollection()->addAction(QLatin1String("go_next_unread_text"), action );
3273  action->setShortcut(QKeySequence(Qt::Key_Space));
3274  action->setHelpText(i18n("Go to the next unread text"));
3275  action->setWhatsThis( i18n("Scroll down current message. "
3276  "If at end of current message, "
3277  "go to next unread message."));
3278  connect(action, SIGNAL(triggered(bool)), SLOT(slotReadOn()));
3279  }
3280 
3281  //----- Settings Menu
3282  {
3283  KAction *action = new KAction(i18n("Configure &Filters..."), this);
3284  action->setMenuRole( QAction::NoRole ); // do not move to application menu on OS X
3285  actionCollection()->addAction(QLatin1String("filter"), action );
3286  connect(action, SIGNAL(triggered(bool)), SLOT(slotFilter()));
3287  }
3288  {
3289  KAction *action = new KAction(i18n("Manage &Sieve Scripts..."), this);
3290  actionCollection()->addAction(QLatin1String("sieveFilters"), action );
3291  connect(action, SIGNAL(triggered(bool)), SLOT(slotManageSieveScripts()));
3292  }
3293  {
3294  mShowIntroductionAction = new KAction(KIcon(QLatin1String("kmail")), i18n("KMail &Introduction"), this);
3295  actionCollection()->addAction(QLatin1String("help_kmail_welcomepage"), mShowIntroductionAction );
3296  mShowIntroductionAction->setHelpText( i18n("Display KMail's Welcome Page") );
3297  connect(mShowIntroductionAction, SIGNAL(triggered(bool)), SLOT(slotIntro()));
3298  mShowIntroductionAction->setEnabled(mMsgView != 0);
3299  }
3300 
3301  // ----- Standard Actions
3302 
3303  // KStandardAction::configureNotifications(this, SLOT(slotEditNotifications()), actionCollection());
3304  {
3305  KAction *action = new KAction( KIcon(QLatin1String("preferences-desktop-notification")),
3306  i18n("Configure &Notifications..."), this );
3307  action->setMenuRole( QAction::NoRole ); // do not move to application menu on OS X
3308  actionCollection()->addAction( QLatin1String("kmail_configure_notifications"), action );
3309  connect(action, SIGNAL(triggered(bool)), SLOT(slotEditNotifications()));
3310  }
3311 
3312  {
3313  KAction *action = new KAction(KIcon(QLatin1String("configure")), i18n("&Configure KMail..."), this);
3314  action->setMenuRole( QAction::PreferencesRole ); // this one should move to the application menu on OS X
3315  actionCollection()->addAction(QLatin1String("kmail_configure_kmail"), action );
3316  connect(action, SIGNAL(triggered(bool)), kmkernel, SLOT(slotShowConfigurationDialog()));
3317  }
3318 
3319  {
3320  mExpireConfigAction = new KAction( i18n( "Expire..." ), this );
3321  actionCollection()->addAction( QLatin1String("expire_settings"),mExpireConfigAction );
3322  connect( mExpireConfigAction, SIGNAL(triggered(bool)), mManageShowCollectionProperties, SLOT(slotShowExpiryProperties()) );
3323  }
3324 
3325  {
3326  KAction *action = new KAction( KIcon( QLatin1String("bookmark-new" )), i18n( "Add Favorite Folder..." ), this );
3327  actionCollection()->addAction( QLatin1String("add_favorite_folder"), action );
3328  connect( action, SIGNAL(triggered(bool)), this, SLOT(slotAddFavoriteFolder()) );
3329  }
3330 
3331  {
3332  mServerSideSubscription = new KAction( KIcon( QLatin1String("folder-bookmarks") ), i18n( "Serverside Subscription..." ), this);
3333  actionCollection()->addAction( QLatin1String("serverside_subscription"), mServerSideSubscription);
3334  connect( mServerSideSubscription, SIGNAL(triggered(bool)), this, SLOT(slotServerSideSubscription()) );
3335  }
3336 
3337 
3338  {
3339  mApplyFiltersOnFolder = new KAction( KIcon( QLatin1String("view-filter") ), i18n( "Appl&y All Filters On Folder" ), this );
3340  actionCollection()->addAction( QLatin1String("apply_filters_on_folder"), mApplyFiltersOnFolder );
3341  connect( mApplyFiltersOnFolder, SIGNAL(triggered(bool)),
3342  SLOT(slotApplyFiltersOnFolder()) );
3343 
3344  }
3345 
3346  {
3347  KAction *action = new KAction(KIcon(QLatin1String("kmail")), i18n("&Export KMail Data..."), this);
3348  actionCollection()->addAction(QLatin1String("kmail_export_data"), action );
3349  connect(action, SIGNAL(triggered(bool)), mLaunchExternalComponent, SLOT(slotExportData()));
3350  }
3351 
3352  {
3353  KAction *action = new KAction(KIcon( QLatin1String( "contact-new" ) ),i18n("New AddressBook Contact..."),this);
3354  actionCollection()->addAction(QLatin1String("kmail_new_addressbook_contact"), action );
3355  connect(action, SIGNAL(triggered(bool)), this, SLOT(slotCreateAddressBookContact()));
3356 
3357 
3358  }
3359 
3360  actionCollection()->addAction(KStandardAction::Undo, QLatin1String("kmail_undo"), this, SLOT(slotUndo()));
3361 
3362  KStandardAction::tipOfDay( mLaunchExternalComponent, SLOT(slotShowTip()), actionCollection() );
3363 
3364  menutimer = new QTimer( this );
3365  menutimer->setObjectName( QLatin1String("menutimer") );
3366  menutimer->setSingleShot( true );
3367  connect( menutimer, SIGNAL(timeout()), SLOT(updateMessageActionsDelayed()) );
3368  connect( kmkernel->undoStack(),
3369  SIGNAL(undoStackChanged()), this, SLOT(slotUpdateUndo()));
3370 
3371  updateMessageActions();
3372  updateFolderMenu();
3373  mTagActionManager = new KMail::TagActionManager( this, actionCollection(), mMsgActions,
3374  mGUIClient );
3375  mFolderShortcutActionManager = new KMail::FolderShortcutActionManager( this, actionCollection() );
3376 
3377  {
3378  KAction *action = new KAction( i18n("Copy Message to Folder"), this );
3379  actionCollection()->addAction(QLatin1String( "copy_message_to_folder"), action );
3380  connect( action, SIGNAL(triggered(bool)),
3381  SLOT(slotCopySelectedMessagesToFolder()) );
3382  action->setShortcut( QKeySequence( Qt::Key_C ) );
3383  }
3384  {
3385  KAction *action = new KAction( i18n("Jump to Folder..."), this );
3386  actionCollection()->addAction( QLatin1String("jump_to_folder"), action );
3387  connect( action, SIGNAL(triggered(bool)),
3388  SLOT(slotJumpToFolder()) );
3389  action->setShortcut( QKeySequence( Qt::Key_J ) );
3390  }
3391  {
3392  KAction *action = new KAction(i18n("Abort Current Operation"), this);
3393  actionCollection()->addAction(QLatin1String("cancel"), action );
3394  connect( action, SIGNAL(triggered(bool)),
3395  ProgressManager::instance(), SLOT(slotAbortAll()) );
3396  action->setShortcut( QKeySequence( Qt::Key_Escape ) );
3397  }
3398  {
3399  KAction *action = new KAction(i18n("Focus on Next Folder"), this);
3400  actionCollection()->addAction(QLatin1String("inc_current_folder"), action );
3401  connect( action, SIGNAL(triggered(bool)),
3402  mFolderTreeWidget->folderTreeView(), SLOT(slotFocusNextFolder()) );
3403  action->setShortcut( QKeySequence( Qt::CTRL+Qt::Key_Right ) );
3404  }
3405  {
3406  KAction *action = new KAction(i18n("Focus on Previous Folder"), this);
3407  actionCollection()->addAction(QLatin1String("dec_current_folder"), action );
3408  connect( action, SIGNAL(triggered(bool)),
3409  mFolderTreeWidget->folderTreeView(), SLOT(slotFocusPrevFolder()) );
3410  action->setShortcut( QKeySequence( Qt::CTRL+Qt::Key_Left ) );
3411  }
3412  {
3413  KAction *action = new KAction(i18n("Select Folder with Focus"), this);
3414  actionCollection()->addAction(QLatin1String("select_current_folder"), action );
3415 
3416  connect( action, SIGNAL(triggered(bool)),
3417  mFolderTreeWidget->folderTreeView(), SLOT(slotSelectFocusFolder()) );
3418  action->setShortcut( QKeySequence( Qt::CTRL+Qt::Key_Space ) );
3419  }
3420  {
3421  KAction *action = new KAction(i18n("Focus on First Folder"), this);
3422  actionCollection()->addAction(QLatin1String("focus_first_folder"), action );
3423  connect( action, SIGNAL(triggered(bool)),
3424  mFolderTreeWidget->folderTreeView(), SLOT(slotFocusFirstFolder()) );
3425  action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Home ) );
3426  }
3427  {
3428  KAction *action = new KAction(i18n("Focus on Last Folder"), this);
3429  actionCollection()->addAction(QLatin1String("focus_last_folder"), action );
3430  connect( action, SIGNAL(triggered(bool)),
3431  mFolderTreeWidget->folderTreeView(), SLOT(slotFocusLastFolder()) );
3432  action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_End ) );
3433  }
3434  {
3435  KAction *action = new KAction(i18n("Focus on Next Message"), this);
3436  actionCollection()->addAction(QLatin1String("inc_current_message"), action );
3437  connect( action, SIGNAL(triggered(bool)),
3438  this, SLOT(slotFocusOnNextMessage()) );
3439  action->setShortcut( QKeySequence( Qt::ALT+Qt::Key_Right ) );
3440  }
3441  {
3442  KAction *action = new KAction(i18n("Focus on Previous Message"), this);
3443  actionCollection()->addAction(QLatin1String("dec_current_message"), action );
3444  connect( action, SIGNAL(triggered(bool)),
3445  this, SLOT(slotFocusOnPrevMessage()) );
3446  action->setShortcut( QKeySequence( Qt::ALT+Qt::Key_Left ) );
3447  }
3448  {
3449  KAction *action = new KAction(i18n("Select First Message"), this);
3450  actionCollection()->addAction(QLatin1String("select_first_message"), action );
3451  connect ( action, SIGNAL(triggered(bool)),
3452  this, SLOT(slotSelectFirstMessage()) );
3453  action->setShortcut( QKeySequence( Qt::ALT + Qt::Key_Home ) );
3454  }
3455  {
3456  KAction *action = new KAction(i18n("Select Last Message"), this);
3457  actionCollection()->addAction(QLatin1String("select_last_message"), action );
3458  connect ( action, SIGNAL(triggered(bool)),
3459  this, SLOT(slotSelectLastMessage()) );
3460  action->setShortcut( QKeySequence( Qt::ALT + Qt::Key_End ) );
3461  }
3462  {
3463  KAction *action = new KAction(i18n("Select Message with Focus"), this);
3464  actionCollection()->addAction( QLatin1String("select_current_message"), action );
3465  connect( action, SIGNAL(triggered(bool)),
3466  this, SLOT(slotSelectFocusedMessage()) );
3467  action->setShortcut( QKeySequence( Qt::ALT+Qt::Key_Space ) );
3468  }
3469 
3470  {
3471  mQuickSearchAction = new KAction( i18n("Set Focus to Quick Search"), this );
3472  //If change shortcut change Panel::setQuickSearchClickMessage(...) message
3473  mQuickSearchAction->setShortcut( QKeySequence( Qt::ALT + Qt::Key_Q ) );
3474  actionCollection()->addAction( QLatin1String("focus_to_quickseach"), mQuickSearchAction );
3475  connect( mQuickSearchAction, SIGNAL(triggered(bool)),
3476  SLOT(slotFocusQuickSearch()) );
3477  updateQuickSearchLineText();
3478  }
3479  {
3480  KAction *action = new KAction( i18n( "Extend Selection to Previous Message" ), this );
3481  action->setShortcut( QKeySequence( Qt::SHIFT + Qt::Key_Left ) );
3482  actionCollection()->addAction( QLatin1String("previous_message"), action );
3483  connect( action, SIGNAL(triggered(bool)),
3484  this, SLOT(slotExtendSelectionToPreviousMessage()) );
3485  }
3486  {
3487  KAction *action = new KAction( i18n( "Extend Selection to Next Message" ), this );
3488  action->setShortcut( QKeySequence( Qt::SHIFT + Qt::Key_Right ) );
3489  actionCollection()->addAction( QLatin1String("next_message"), action );
3490  connect( action, SIGNAL(triggered(bool)),
3491  this, SLOT(slotExtendSelectionToNextMessage()) );
3492  }
3493 
3494  {
3495  mMoveMsgToFolderAction = new KAction( i18n("Move Message to Folder"), this );
3496  mMoveMsgToFolderAction->setShortcut( QKeySequence( Qt::Key_M ) );
3497  actionCollection()->addAction( QLatin1String("move_message_to_folder"), mMoveMsgToFolderAction );
3498  connect( mMoveMsgToFolderAction, SIGNAL(triggered(bool)),
3499  SLOT(slotMoveSelectedMessageToFolder()) );
3500  }
3501 
3502  mArchiveAction = new KAction( i18nc("@action", "Archive"), this);
3503  actionCollection()->addAction( QLatin1String("archive_mails"), mArchiveAction );
3504  connect( mArchiveAction, SIGNAL(triggered(bool)),
3505  SLOT(slotArchiveMails()) );
3506 
3507 
3508 }
3509 
3510 void KMMainWidget::slotAddFavoriteFolder()
3511 {
3512  if (!mFavoritesModel)
3513  return;
3514  QPointer<MailCommon::FolderSelectionDialog> dialog( selectFromAllFoldersDialog() );
3515  dialog->setCaption( i18n("Add Favorite Folder") );
3516  if ( dialog->exec() && dialog ) {
3517  const Akonadi::Collection collection = dialog->selectedCollection();
3518  if ( collection.isValid() ) {
3519  mFavoritesModel->addCollection( collection );
3520  }
3521  }
3522 }
3523 
3524 //-----------------------------------------------------------------------------
3525 void KMMainWidget::slotEditNotifications()
3526 {
3527  KMail::KMKnotify notifyDlg( this );
3528  notifyDlg.exec();
3529 }
3530 
3531 //-----------------------------------------------------------------------------
3532 void KMMainWidget::slotReadOn()
3533 {
3534  if ( !mMsgView )
3535  return;
3536  if ( !mMsgView->viewer()->atBottom() ) {
3537  mMsgView->viewer()->slotJumpDown();
3538  return;
3539  }
3540  slotSelectNextUnreadMessage();
3541 }
3542 
3543 void KMMainWidget::slotNextUnreadFolder()
3544 {
3545  if ( !mFolderTreeWidget )
3546  return;
3547  mGoToFirstUnreadMessageInSelectedFolder = true;
3548  mFolderTreeWidget->folderTreeView()->selectNextUnreadFolder();
3549  mGoToFirstUnreadMessageInSelectedFolder = false;
3550 }
3551 
3552 void KMMainWidget::slotPrevUnreadFolder()
3553 {
3554  if ( !mFolderTreeWidget )
3555  return;
3556  mGoToFirstUnreadMessageInSelectedFolder = true;
3557  mFolderTreeWidget->folderTreeView()->selectPrevUnreadFolder();
3558  mGoToFirstUnreadMessageInSelectedFolder = false;
3559 }
3560 
3561 void KMMainWidget::slotExpandThread()
3562 {
3563  mMessagePane->setCurrentThreadExpanded( true );
3564 }
3565 
3566 void KMMainWidget::slotCollapseThread()
3567 {
3568  mMessagePane->setCurrentThreadExpanded( false );
3569 }
3570 
3571 void KMMainWidget::slotExpandAllThreads()
3572 {
3573  // TODO: Make this asynchronous ? (if there is enough demand)
3574 #ifndef QT_NO_CURSOR
3575  MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() );
3576 #endif
3577  mMessagePane->setAllThreadsExpanded( true );
3578 }
3579 
3580 void KMMainWidget::slotCollapseAllThreads()
3581 {
3582  // TODO: Make this asynchronous ? (if there is enough demand)
3583 #ifndef QT_NO_CURSOR
3584  MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() );
3585 #endif
3586  mMessagePane->setAllThreadsExpanded( false );
3587 }
3588 
3589 //-----------------------------------------------------------------------------
3590 void KMMainWidget::updateMessageMenu()
3591 {
3592  updateMessageActions();
3593 }
3594 
3595 void KMMainWidget::startUpdateMessageActionsTimer()
3596 {
3597  // FIXME: This delay effectively CAN make the actions to be in an incoherent state
3598  // Maybe we should mark actions as "dirty" here and check it in every action handler...
3599  updateMessageActions( true );
3600 
3601  menutimer->stop();
3602  menutimer->start( 500 );
3603 }
3604 
3605 void KMMainWidget::updateMessageActions( bool fast )
3606 {
3607  Akonadi::Item::List selectedItems;
3608  Akonadi::Item::List selectedVisibleItems;
3609  bool allSelectedBelongToSameThread = false;
3610  if (mCurrentFolder && mCurrentFolder->isValid() &&
3611  mMessagePane->getSelectionStats( selectedItems, selectedVisibleItems, &allSelectedBelongToSameThread )
3612  )
3613  {
3614  mMsgActions->setCurrentMessage( mMessagePane->currentItem(), selectedVisibleItems );
3615  } else {
3616  mMsgActions->setCurrentMessage( Akonadi::Item() );
3617  }
3618 
3619  if ( !fast )
3620  updateMessageActionsDelayed();
3621 
3622 }
3623 
3624 
3625 void KMMainWidget::updateMessageActionsDelayed()
3626 {
3627  int count;
3628  Akonadi::Item::List selectedItems;
3629  Akonadi::Item::List selectedVisibleItems;
3630  bool allSelectedBelongToSameThread = false;
3631  Akonadi::Item currentMessage;
3632  if (mCurrentFolder && mCurrentFolder->isValid() &&
3633  mMessagePane->getSelectionStats( selectedItems, selectedVisibleItems, &allSelectedBelongToSameThread )
3634  )
3635  {
3636  count = selectedItems.count();
3637 
3638  currentMessage = mMessagePane->currentItem();
3639 
3640  } else {
3641  count = 0;
3642  currentMessage = Akonadi::Item();
3643  }
3644 
3645  mApplyFiltersOnFolder->setEnabled( mCurrentFolder && mCurrentFolder->isValid() );
3646 
3647  //
3648  // Here we have:
3649  //
3650  // - A list of selected messages stored in selectedSernums.
3651  // The selected messages might contain some invisible ones as a selected
3652  // collapsed node "includes" all the children in the selection.
3653  // - A list of selected AND visible messages stored in selectedVisibleSernums.
3654  // This list does not contain children of selected and collapsed nodes.
3655  //
3656  // Now, actions can operate on:
3657  // - Any set of messages
3658  // These are called "mass actions" and are enabled whenever we have a message selected.
3659  // In fact we should differentiate between actions that operate on visible selection
3660  // and those that operate on the selection as a whole (without considering visibility)...
3661  // - A single thread
3662  // These are called "thread actions" and are enabled whenever all the selected messages belong
3663  // to the same thread. If the selection doesn't cover the whole thread then the action
3664  // will act on the whole thread anyway (thus will silently extend the selection)
3665  // - A single message
3666  // And we have two sub-cases:
3667  // - The selection must contain exactly one message
3668  // These actions can't ignore the hidden messages and thus must be disabled if
3669  // the selection contains any.
3670  // - The selection must contain exactly one visible message
3671  // These actions will ignore the hidden message and thus can be enabled if
3672  // the selection contains any.
3673  //
3674 
3675  bool readOnly = mCurrentFolder && mCurrentFolder->isValid() && ( mCurrentFolder->rights() & Akonadi::Collection::ReadOnly );
3676  // can we apply strictly single message actions ? (this is false if the whole selection contains more than one message)
3677  bool single_actions = count == 1;
3678  // can we apply loosely single message actions ? (this is false if the VISIBLE selection contains more than one message)
3679  bool singleVisibleMessageSelected = selectedVisibleItems.count() == 1;
3680  // can we apply "mass" actions to the selection ? (this is actually always true if the selection is non-empty)
3681  bool mass_actions = count >= 1;
3682  // does the selection identify a single thread ?
3683  bool thread_actions = mass_actions && allSelectedBelongToSameThread && mMessagePane->isThreaded();
3684  // can we apply flags to the selected messages ?
3685  bool flags_available = GlobalSettings::self()->allowLocalFlags() || !(mCurrentFolder && mCurrentFolder->isValid() ? readOnly : true);
3686 
3687  mThreadStatusMenu->setEnabled( thread_actions );
3688  // these need to be handled individually, the user might have them
3689  // in the toolbar
3690  mWatchThreadAction->setEnabled( thread_actions && flags_available );
3691  mIgnoreThreadAction->setEnabled( thread_actions && flags_available );
3692  mMarkThreadAsReadAction->setEnabled( thread_actions );
3693  mMarkThreadAsUnreadAction->setEnabled( thread_actions );
3694  mToggleThreadToActAction->setEnabled( thread_actions && flags_available );
3695  mToggleThreadImportantAction->setEnabled( thread_actions && flags_available );
3696  bool canDeleteMessages = mCurrentFolder && mCurrentFolder->isValid() && ( mCurrentFolder->rights() & Akonadi::Collection::CanDeleteItem );
3697 
3698  mTrashThreadAction->setEnabled( thread_actions && canDeleteMessages );
3699  mDeleteThreadAction->setEnabled( thread_actions && canDeleteMessages );
3700 
3701  if ( currentMessage.isValid() )
3702  {
3703  MessageStatus status;
3704  status.setStatusFromFlags( currentMessage.flags() );
3705  mTagActionManager->updateActionStates ( count, mMessagePane->currentItem() );
3706  if (thread_actions)
3707  {
3708  mToggleThreadToActAction->setChecked( status.isToAct() );
3709  mToggleThreadImportantAction->setChecked( status.isImportant() );
3710  mWatchThreadAction->setChecked( status.isWatched() );
3711  mIgnoreThreadAction->setChecked( status.isIgnored() );
3712  }
3713  }
3714 
3715  mMoveActionMenu->setEnabled( mass_actions && canDeleteMessages );
3716  if (mMoveMsgToFolderAction)
3717  mMoveMsgToFolderAction->setEnabled( mass_actions && canDeleteMessages );
3718  //mCopyActionMenu->setEnabled( mass_actions );
3719 
3720  mDeleteAction->setEnabled( mass_actions && canDeleteMessages );
3721 
3722  mExpireConfigAction->setEnabled( canDeleteMessages );
3723 
3724  if ( mMsgView ) {
3725  mMsgView->findInMessageAction()->setEnabled( mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) );
3726  }
3727  mMsgActions->forwardInlineAction()->setEnabled( mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) );
3728  mMsgActions->forwardAttachedAction()->setEnabled( mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) );
3729  mMsgActions->forwardMenu()->setEnabled( mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) );
3730 
3731  mMsgActions->editAction()->setEnabled( single_actions );
3732  mUseAction->setEnabled( single_actions && CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) );
3733  filterMenu()->setEnabled( single_actions );
3734  mMsgActions->redirectAction()->setEnabled( /*single_actions &&*/mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) );
3735 
3736  if ( mMsgActions->customTemplatesMenu() )
3737  {
3738  mMsgActions->customTemplatesMenu()->forwardActionMenu()->setEnabled( mass_actions );
3739  mMsgActions->customTemplatesMenu()->replyActionMenu()->setEnabled( single_actions );
3740  mMsgActions->customTemplatesMenu()->replyAllActionMenu()->setEnabled( single_actions );
3741  }
3742 
3743  // "Print" will act on the current message: it will ignore any hidden selection
3744  mMsgActions->printAction()->setEnabled( singleVisibleMessageSelected );
3745  // "Print preview" will act on the current message: it will ignore any hidden selection
3746  KAction *printPreviewAction = mMsgActions->printPreviewAction();
3747  if (printPreviewAction)
3748  printPreviewAction->setEnabled( singleVisibleMessageSelected );
3749 
3750  // "View Source" will act on the current message: it will ignore any hidden selection
3751  if (mMsgView) {
3752  mMsgView->viewSourceAction()->setEnabled( singleVisibleMessageSelected );
3753  }
3754  MessageStatus status;
3755  status.setStatusFromFlags( currentMessage.flags() );
3756 
3757  QList< QAction *> actionList;
3758  bool statusSendAgain = single_actions && ( ( currentMessage.isValid() && status.isSent() ) || ( currentMessage.isValid() && CommonKernel->folderIsSentMailFolder( mCurrentFolder->collection() ) ) );
3759  if ( statusSendAgain ) {
3760  actionList << mSendAgainAction;
3761  } else if ( single_actions ) {
3762  actionList << messageActions()->editAction();
3763  }
3764  actionList << mSaveAttachmentsAction;
3765  if (mCurrentFolder && FolderArchive::FolderArchiveUtil::resourceSupportArchiving(mCurrentFolder->collection().resource()))
3766  actionList << mArchiveAction;
3767  mGUIClient->unplugActionList( QLatin1String( "messagelist_actionlist" ) );
3768  mGUIClient->plugActionList( QLatin1String( "messagelist_actionlist" ), actionList );
3769  mSendAgainAction->setEnabled( statusSendAgain );
3770 
3771  mSaveAsAction->setEnabled( mass_actions );
3772 
3773  if ((mCurrentFolder&& mCurrentFolder->isValid())) {
3774  updateMoveAction( mCurrentFolder->statistics() );
3775  }
3776  else {
3777  updateMoveAction(false,false);
3778  }
3779 
3780  const qint64 nbMsgOutboxCollection = MailCommon::Util::updatedCollection( CommonKernel->outboxCollectionFolder() ).statistics().count();
3781 
3782  mSendQueued->setEnabled( nbMsgOutboxCollection > 0 );
3783  mSendActionMenu->setEnabled( nbMsgOutboxCollection > 0 );
3784 
3785  const bool newPostToMailingList = mCurrentFolder && mCurrentFolder->isMailingListEnabled();
3786  mMessageNewList->setEnabled(newPostToMailingList);
3787 
3788  slotUpdateOnlineStatus( static_cast<GlobalSettingsBase::EnumNetworkState::type>( GlobalSettings::self()->networkState() ) );
3789  if (action( QLatin1String("kmail_undo") ))
3790  action( QLatin1String("kmail_undo") )->setEnabled( kmkernel->undoStack()->size() > 0 );
3791 
3792  // Enable / disable all filters.
3793  foreach ( QAction *filterAction, mFilterMenuActions ) {
3794  filterAction->setEnabled( count > 0 );
3795  }
3796 
3797  mApplyAllFiltersAction->setEnabled( count);
3798  mApplyFilterActionsMenu->setEnabled( count );
3799 }
3800 
3801 
3802 void KMMainWidget::slotAkonadiStandardActionUpdated()
3803 {
3804  bool multiFolder = false;
3805  if ( mFolderTreeWidget ) {
3806  multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3807  }
3808  if ( mCollectionProperties ) {
3809  if ( mCurrentFolder && mCurrentFolder->collection().isValid() ) {
3810  const Akonadi::AgentInstance instance =
3811  Akonadi::AgentManager::self()->instance( mCurrentFolder->collection().resource() );
3812 
3813  mCollectionProperties->setEnabled( !multiFolder &&
3814  !mCurrentFolder->isStructural() &&
3815  (instance.status()!=Akonadi::AgentInstance::Broken) );
3816  } else {
3817  mCollectionProperties->setEnabled(false);
3818  }
3819  QList< QAction* > collectionProperties;
3820  if ( mCollectionProperties->isEnabled() )
3821  collectionProperties << mCollectionProperties;
3822  mGUIClient->unplugActionList( QLatin1String("akonadi_collection_collectionproperties_actionlist") );
3823  mGUIClient->plugActionList( QLatin1String("akonadi_collection_collectionproperties_actionlist"), collectionProperties );
3824 
3825  }
3826 
3827  const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural();
3828 
3829  if ( mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::DeleteCollections ) ) {
3830 
3831  mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::DeleteCollections )->setEnabled( mCurrentFolder
3832  && !multiFolder
3833  && ( mCurrentFolder->collection().rights() & Collection::CanDeleteCollection )
3834  && !mCurrentFolder->isSystemFolder()
3835  && folderWithContent);
3836  }
3837 
3838  if ( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash ) ) {
3839  mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash )->setEnabled( folderWithContent
3840  && ( mCurrentFolder->count() > 0 )
3841  && mCurrentFolder->canDeleteMessages()
3842  && !multiFolder );
3843  mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash )->setText( (mCurrentFolder && CommonKernel->folderIsTrash(mCurrentFolder->collection())) ? i18n("E&mpty Trash") : i18n("&Move All Messages to Trash") );
3844  }
3845 
3846 
3847  QList< QAction* > addToFavorite;
3848  QAction *actionAddToFavoriteCollections = akonadiStandardAction( Akonadi::StandardActionManager::AddToFavoriteCollections );
3849  if ( actionAddToFavoriteCollections ) {
3850  if ( mEnableFavoriteFolderView && actionAddToFavoriteCollections->isEnabled() )
3851  addToFavorite << actionAddToFavoriteCollections;
3852  mGUIClient->unplugActionList( QLatin1String("akonadi_collection_add_to_favorites_actionlist") );
3853  mGUIClient->plugActionList( QLatin1String("akonadi_collection_add_to_favorites_actionlist"), addToFavorite );
3854  }
3855 
3856  QList< QAction* > syncActionList;
3857  QAction *actionSync = akonadiStandardAction( Akonadi::StandardActionManager::SynchronizeCollections );
3858  if ( actionSync && actionSync->isEnabled() ) {
3859  syncActionList << actionSync;
3860  }
3861  actionSync = akonadiStandardAction( Akonadi::StandardActionManager::SynchronizeCollectionsRecursive );
3862  if ( actionSync && actionSync->isEnabled() ) {
3863  syncActionList << actionSync;
3864  }
3865  mGUIClient->unplugActionList( QLatin1String("akonadi_collection_sync_actionlist") );
3866  mGUIClient->plugActionList( QLatin1String("akonadi_collection_sync_actionlist"), syncActionList );
3867 
3868 
3869 
3870  QList< QAction* > actionList;
3871 
3872  QAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CreateCollection );
3873  if ( action && action->isEnabled() ) {
3874  actionList << action;
3875  }
3876 
3877  action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::MoveCollectionToMenu );
3878  if ( action && action->isEnabled() ) {
3879  actionList <<action;
3880  }
3881 
3882  action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyCollectionToMenu);
3883  if ( action && action->isEnabled() ) {
3884  actionList <<action;
3885  }
3886  mGUIClient->unplugActionList( QLatin1String("akonadi_collection_move_copy_menu_actionlist") );
3887  mGUIClient->plugActionList( QLatin1String("akonadi_collection_move_copy_menu_actionlist"), actionList );
3888 
3889 
3890 }
3891 
3892 void KMMainWidget::updateHtmlMenuEntry()
3893 {
3894  if (mDisplayMessageFormatMenu && mPreferHtmlLoadExtAction) {
3895  bool multiFolder = false;
3896  if ( mFolderTreeWidget ) {
3897  multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3898  }
3899  // the visual ones only make sense if we are showing a message list
3900  const bool enabledAction = ( mFolderTreeWidget &&
3901  mFolderTreeWidget->folderTreeView()->currentFolder().isValid() &&
3902  !multiFolder );
3903 
3904  mDisplayMessageFormatMenu->setEnabled(enabledAction);
3905  const bool isEnabled = ( mFolderTreeWidget &&
3906  mFolderTreeWidget->folderTreeView()->currentFolder().isValid() &&
3907  !multiFolder);
3908  const bool useHtml = (mFolderDisplayFormatPreference == MessageViewer::Viewer::Html || (mHtmlGlobalSetting && mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting));
3909  mPreferHtmlLoadExtAction->setEnabled( isEnabled && useHtml );
3910 
3911  mDisplayMessageFormatMenu->setDisplayMessageFormat(mFolderDisplayFormatPreference);
3912 
3913  mPreferHtmlLoadExtAction->setChecked( !multiFolder && ( mHtmlLoadExtGlobalSetting ? !mFolderHtmlLoadExtPreference : mFolderHtmlLoadExtPreference ) );
3914  }
3915 }
3916 
3917 //-----------------------------------------------------------------------------
3918 void KMMainWidget::updateFolderMenu()
3919 {
3920  if (!CommonKernel->outboxCollectionFolder().isValid()) {
3921  QTimer::singleShot(1000,this,SLOT(updateFolderMenu()));
3922  return;
3923  }
3924 
3925  const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural();
3926  bool multiFolder = false;
3927  if ( mFolderTreeWidget ) {
3928  multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3929  }
3930  mFolderMailingListPropertiesAction->setEnabled( folderWithContent &&
3931  !multiFolder &&
3932  !mCurrentFolder->isSystemFolder() );
3933 
3934  QList< QAction* > actionlist;
3935  if ( mCurrentFolder && mCurrentFolder->collection().id() == CommonKernel->outboxCollectionFolder().id() && (mCurrentFolder->collection()).statistics().count() > 0) {
3936  kDebug() << "Enabling send queued";
3937  mSendQueued->setEnabled(true);
3938  actionlist << mSendQueued;
3939  }
3940  // if ( mCurrentFolder && mCurrentFolder->collection().id() != CommonKernel->trashCollectionFolder().id() ) {
3941  // actionlist << mTrashAction;
3942  // }
3943  mGUIClient->unplugActionList( QLatin1String( "outbox_folder_actionlist" ) );
3944  mGUIClient->plugActionList( QLatin1String( "outbox_folder_actionlist" ), actionlist );
3945  actionlist.clear();
3946 
3947  const bool isASearchFolder = mCurrentFolder && mCurrentFolder->collection().resource() == QLatin1String( "akonadi_search_resource" );
3948  if (isASearchFolder)
3949  mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::DeleteCollections )->setText( i18n("&Delete Search") );
3950 
3951  mArchiveFolderAction->setEnabled( mCurrentFolder && !multiFolder && folderWithContent );
3952 
3953  bool isInTrashFolder = (mCurrentFolder && CommonKernel->folderIsTrash(mCurrentFolder->collection()));
3954  KAction *moveToTrash = akonadiStandardAction( Akonadi::StandardMailActionManager::MoveToTrash );
3955  moveToTrash->setText( isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "&Delete"): i18n("&Move to Trash") );
3956  moveToTrash->setIcon( isInTrashFolder ? KIcon(QLatin1String("edit-delete")) : KIcon(QLatin1String("user-trash") ));
3957  //Use same text as in Text property. Change it in kf5
3958  moveToTrash->setToolTip( isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "&Delete"): i18n("&Move to Trash") );
3959  mTrashThreadAction->setText(isInTrashFolder ?i18n("Delete T&hread"): i18n("M&ove Thread to Trash"));
3960  mTrashThreadAction->setIcon(isInTrashFolder ? KIcon(QLatin1String("edit-delete") ) : KIcon(QLatin1String("user-trash") ) );
3961 
3962  mSearchMessages->setText( (mCurrentFolder && mCurrentFolder->collection().resource() == QLatin1String( "akonadi_search_resource" )) ? i18n("Edit Search...") : i18n("&Find Messages...") );
3963 
3964 
3965  mExpireConfigAction->setEnabled( mCurrentFolder &&
3966  !mCurrentFolder->isStructural() &&
3967  !multiFolder &&
3968  mCurrentFolder->canDeleteMessages() &&
3969  folderWithContent &&
3970  !MailCommon::Util::isVirtualCollection( mCurrentFolder->collection() ) );
3971 
3972  updateHtmlMenuEntry();
3973 
3974  mShowFolderShortcutDialogAction->setEnabled( !multiFolder && folderWithContent );
3975 
3976  actionlist << akonadiStandardAction( Akonadi::StandardActionManager::ManageLocalSubscriptions );
3977  bool imapFolderIsOnline = false;
3978  if (mCurrentFolder && kmkernel->isImapFolder( mCurrentFolder->collection(),imapFolderIsOnline )) {
3979  if (imapFolderIsOnline) {
3980  actionlist << mServerSideSubscription;
3981  }
3982  }
3983 
3984  mGUIClient->unplugActionList( QLatin1String( "collectionview_actionlist" ) );
3985  mGUIClient->plugActionList( QLatin1String( "collectionview_actionlist" ), actionlist );
3986 
3987 }
3988 
3989 //-----------------------------------------------------------------------------
3990 void KMMainWidget::slotIntro()
3991 {
3992  if ( !mMsgView )
3993  return;
3994 
3995  mMsgView->clear( true );
3996 
3997  // hide widgets that are in the way:
3998  if ( mMessagePane && mLongFolderList )
3999  mMessagePane->hide();
4000  mMsgView->displayAboutPage();
4001 
4002  mCurrentFolder.clear();
4003 }
4004 
4005 void KMMainWidget::slotShowStartupFolder()
4006 {
4007  connect( MailCommon::FilterManager::instance(), SIGNAL(filtersChanged()),
4008  this, SLOT(initializeFilterActions()) );
4009  // Plug various action lists. This can't be done in the constructor, as that is called before
4010  // the main window or Kontact calls createGUI().
4011  // This function however is called with a single shot timer.
4012  checkAkonadiServerManagerState();
4013  mFolderShortcutActionManager->createActions();
4014  mTagActionManager->createActions();
4015  messageActions()->setupForwardingActionsList( mGUIClient );
4016 
4017  QString newFeaturesMD5 = KMReaderWin::newFeaturesMD5();
4018  if ( kmkernel->firstStart() ||
4019  GlobalSettings::self()->previousNewFeaturesMD5() != newFeaturesMD5 ) {
4020  GlobalSettings::self()->setPreviousNewFeaturesMD5( newFeaturesMD5 );
4021  slotIntro();
4022  return;
4023  }
4024 }
4025 
4026 void KMMainWidget::checkAkonadiServerManagerState()
4027 {
4028  Akonadi::ServerManager::State state = Akonadi::ServerManager::self()->state();
4029  if (state == Akonadi::ServerManager::Running) {
4030  initializeFilterActions();
4031  } else {
4032  connect( Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)),
4033  SLOT(slotServerStateChanged(Akonadi::ServerManager::State)) );
4034  }
4035 }
4036 
4037 void KMMainWidget::slotServerStateChanged(Akonadi::ServerManager::State state)
4038 {
4039  if (state == Akonadi::ServerManager::Running) {
4040  initializeFilterActions();
4041  disconnect( Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)));
4042  }
4043 }
4044 
4045 QList<KActionCollection*> KMMainWidget::actionCollections() const {
4046  return QList<KActionCollection*>() << actionCollection();
4047 }
4048 
4049 //-----------------------------------------------------------------------------
4050 void KMMainWidget::slotUpdateUndo()
4051 {
4052  if ( actionCollection()->action( QLatin1String("kmail_undo") ) ) {
4053  QAction *act = actionCollection()->action( QLatin1String("kmail_undo") );
4054  act->setEnabled( !kmkernel->undoStack()->isEmpty());
4055  const QString infoStr = kmkernel->undoStack()->undoInfo();
4056  if (infoStr.isEmpty()) {
4057  act->setText(i18n("&Undo"));
4058  } else {
4059  act->setText(i18n("&Undo: \"%1\"", kmkernel->undoStack()->undoInfo()));
4060  }
4061  }
4062 }
4063 
4064 //-----------------------------------------------------------------------------
4065 void KMMainWidget::clearFilterActions()
4066 {
4067  if ( !mFilterTBarActions.isEmpty() )
4068  if ( mGUIClient->factory() )
4069  mGUIClient->unplugActionList( QLatin1String("toolbar_filter_actions") );
4070 
4071  if ( !mFilterMenuActions.isEmpty() )
4072  if ( mGUIClient->factory() )
4073  mGUIClient->unplugActionList( QLatin1String("menu_filter_actions") );
4074 
4075  foreach ( QAction *a, mFilterMenuActions )
4076  actionCollection()->removeAction( a );
4077 
4078  mApplyFilterActionsMenu->menu()->clear();
4079  mFilterTBarActions.clear();
4080  mFilterMenuActions.clear();
4081 
4082  qDeleteAll( mFilterCommands );
4083  mFilterCommands.clear();
4084 }
4085 
4086 //-----------------------------------------------------------------------------
4087 void KMMainWidget::initializeFilterActions()
4088 {
4089  clearFilterActions();
4090  mApplyFilterActionsMenu->menu()->addAction( mApplyAllFiltersAction );
4091  bool addedSeparator = false;
4092 
4093  foreach ( MailFilter *filter, MailCommon::FilterManager::instance()->filters() ) {
4094  if ( !filter->isEmpty() && filter->configureShortcut() && filter->isEnabled() ) {
4095  QString filterName = QString::fromLatin1( "Filter %1").arg( filter->name() );
4096  QString normalizedName = filterName.replace(QLatin1Char(' '), QLatin1Char('_'));
4097  if ( action( normalizedName ) ) {
4098  continue;
4099  }
4100  KMMetaFilterActionCommand *filterCommand = new KMMetaFilterActionCommand( filter->identifier(), this );
4101  mFilterCommands.append( filterCommand );
4102  QString displayText = i18n( "Filter %1", filter->name() );
4103  QString icon = filter->icon();
4104  if ( icon.isEmpty() ) {
4105  icon = QLatin1String("system-run");
4106  }
4107  KAction *filterAction = new KAction( KIcon( icon ), displayText, actionCollection() );
4108  filterAction->setIconText( filter->toolbarName() );
4109 
4110  // The shortcut configuration is done in the filter dialog.
4111  // The shortcut set in the shortcut dialog would not be saved back to
4112  // the filter settings correctly.
4113  filterAction->setShortcutConfigurable( false );
4114  actionCollection()->addAction( normalizedName,
4115  filterAction );
4116  connect( filterAction, SIGNAL(triggered(bool)),
4117  filterCommand, SLOT(start()) );
4118  filterAction->setShortcuts( filter->shortcut() );
4119  if ( !addedSeparator ) {
4120  QAction *a = mApplyFilterActionsMenu->menu()->addSeparator();
4121  mFilterMenuActions.append( a );
4122  addedSeparator = true;
4123  }
4124  mApplyFilterActionsMenu->menu()->addAction( filterAction );
4125  mFilterMenuActions.append( filterAction );
4126  if ( filter->configureToolbar() ) {
4127  mFilterTBarActions.append( filterAction );
4128  }
4129  }
4130  }
4131  if ( !mFilterMenuActions.isEmpty() && mGUIClient->factory() )
4132  mGUIClient->plugActionList( QLatin1String("menu_filter_actions"), mFilterMenuActions );
4133  if ( !mFilterTBarActions.isEmpty() && mGUIClient->factory() ) {
4134  mFilterTBarActions.prepend( mToolbarActionSeparator );
4135  mGUIClient->plugActionList( QLatin1String("toolbar_filter_actions"), mFilterTBarActions );
4136  }
4137 
4138  // Our filters have changed, now enable/disable them
4139  updateMessageActions();
4140 }
4141 
4142 //-----------------------------------------------------------------------------
4143 void KMMainWidget::updateFileMenu()
4144 {
4145  const bool isEmpty = MailCommon::Util::agentInstances().isEmpty();
4146  actionCollection()->action(QLatin1String("check_mail"))->setEnabled( !isEmpty );
4147  actionCollection()->action(QLatin1String("check_mail_in"))->setEnabled( !isEmpty );
4148 }
4149 
4150 //-----------------------------------------------------------------------------
4151 const KMMainWidget::PtrList * KMMainWidget::mainWidgetList()
4152 {
4153  // better safe than sorry; check whether the global static has already been destroyed
4154  if ( theMainWidgetList.isDestroyed() )
4155  {
4156  return 0;
4157  }
4158  return theMainWidgetList;
4159 }
4160 
4161 QSharedPointer<FolderCollection> KMMainWidget::currentFolder() const
4162 {
4163  return mCurrentFolder;
4164 }
4165 
4166 //-----------------------------------------------------------------------------
4167 QString KMMainWidget::overrideEncoding() const
4168 {
4169  if ( mMsgView )
4170  return mMsgView->overrideEncoding();
4171  else
4172  return MessageCore::GlobalSettings::self()->overrideCharacterEncoding();
4173 }
4174 
4175 void KMMainWidget::showEvent( QShowEvent *event )
4176 {
4177  QWidget::showEvent( event );
4178  mWasEverShown = true;
4179 }
4180 
4181 void KMMainWidget::slotRequestFullSearchFromQuickSearch()
4182 {
4183  // First, open the search window. If we are currently on a search folder,
4184  // the search associated with that will be loaded.
4185  if ( !slotSearch() )
4186  return;
4187 
4188  assert( mSearchWin );
4189 
4190  // Now we look at the current state of the quick search, and if there's
4191  // something in there, we add the criteria to the existing search for
4192  // the search folder, if applicable, or make a new one from it.
4193  SearchPattern pattern;
4194  const QString searchString = mMessagePane->currentFilterSearchString();
4195  if ( !searchString.isEmpty() ) {
4196  MessageList::Core::QuickSearchLine::SearchOptions options = mMessagePane->currentOptions();
4197  QByteArray searchStringVal;
4198  if (options & MessageList::Core::QuickSearchLine::SearchEveryWhere) {
4199  searchStringVal = "<message>";
4200  } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstSubject) {
4201  searchStringVal = "subject";
4202  } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstBody) {
4203  searchStringVal = "<body>";
4204  } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstFrom) {
4205  searchStringVal = "from";
4206  } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstBcc) {
4207  searchStringVal = "bcc";
4208  } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstTo) {
4209  searchStringVal = "to";
4210  } else {
4211  searchStringVal = "<message>";
4212  }
4213  pattern.append( SearchRule::createInstance( searchStringVal, SearchRule::FuncContains, searchString ) );
4214  QList<MessageStatus> statusList = mMessagePane->currentFilterStatus();
4215  Q_FOREACH(MessageStatus status, statusList) {
4216  if ( status.hasAttachment() ) {
4217  pattern.append( SearchRule::createInstance( searchStringVal, SearchRule::FuncHasAttachment, searchString ) );
4218  status.setHasAttachment( false );
4219  }
4220  if ( !status.isOfUnknownStatus() ) {
4221  pattern.append( SearchRule::Ptr( new SearchRuleStatus( status ) ) );
4222  }
4223  }
4224  }
4225  if ( !pattern.isEmpty() )
4226  mSearchWin->addRulesToSearchPattern( pattern );
4227 }
4228 
4229 void KMMainWidget::updateVacationScriptStatus( bool active, const QString &serverName )
4230 {
4231  mVacationScriptIndicator->setVacationScriptActive(active, serverName);
4232  mVacationIndicatorActive = mVacationScriptIndicator->hasVacationScriptActive();
4233 }
4234 
4235 QWidget * KMMainWidget::vacationScriptIndicator() const
4236 {
4237  return mVacationScriptIndicator;
4238 }
4239 
4240 void KMMainWidget::updateVacationScriptStatus()
4241 {
4242  updateVacationScriptStatus( mVacationIndicatorActive );
4243 }
4244 
4245 KMail::TagActionManager *KMMainWidget::tagActionManager() const
4246 {
4247  return mTagActionManager;
4248 }
4249 
4250 KMail::FolderShortcutActionManager *KMMainWidget::folderShortcutActionManager() const
4251 {
4252  return mFolderShortcutActionManager;
4253 }
4254 
4255 void KMMainWidget::slotMessageSelected(const Akonadi::Item &item)
4256 {
4257  delete mShowBusySplashTimer;
4258  mShowBusySplashTimer = 0;
4259  if ( mMsgView ) {
4260  // The current selection was cleared, so we'll remove the previously
4261  // selected message from the preview pane
4262  if ( !item.isValid() ) {
4263  mMsgView->clear();
4264  } else {
4265  mShowBusySplashTimer = new QTimer( this );
4266  mShowBusySplashTimer->setSingleShot( true );
4267  connect( mShowBusySplashTimer, SIGNAL(timeout()), this, SLOT(slotShowBusySplash()) );
4268  mShowBusySplashTimer->start( GlobalSettings::self()->folderLoadingTimeout() ); //TODO: check if we need a different timeout setting for this
4269 
4270  Akonadi::ItemFetchJob *itemFetchJob = MessageViewer::Viewer::createFetchJob( item );
4271  if (mCurrentFolder) {
4272  const QString resource = mCurrentFolder->collection().resource();
4273  itemFetchJob->setProperty( "_resource", QVariant::fromValue(resource) );
4274  connect( itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)),
4275  SLOT(itemsReceived(Akonadi::Item::List)) );
4276  connect( itemFetchJob, SIGNAL(result(KJob*)), SLOT(itemsFetchDone(KJob*)) );
4277  }
4278  }
4279  }
4280 }
4281 
4282 void KMMainWidget::itemsReceived(const Akonadi::Item::List &list )
4283 {
4284  Q_ASSERT( list.size() == 1 );
4285  delete mShowBusySplashTimer;
4286  mShowBusySplashTimer = 0;
4287 
4288  if ( !mMsgView )
4289  return;
4290 
4291  Item item = list.first();
4292 
4293  if ( mMessagePane ) {
4294  mMessagePane->show();
4295 
4296  if ( mMessagePane->currentItem() != item ) {
4297  // The user has selected another email already, so don't render this one.
4298  // Mark it as read, though, if the user settings say so.
4299  if ( MessageViewer::GlobalSettings::self()->delayedMarkAsRead() &&
4300  MessageViewer::GlobalSettings::self()->delayedMarkTime() == 0 ) {
4301  item.setFlag( Akonadi::MessageFlags::Seen );
4302  Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob( item, this );
4303  modifyJob->disableRevisionCheck();
4304  modifyJob->setIgnorePayload( true );
4305  }
4306  return;
4307  }
4308  }
4309 
4310  mMsgView->setMessage( item );
4311  // reset HTML override to the folder setting
4312  mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
4313  mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
4314  mMsgView->setDecryptMessageOverwrite( false );
4315  mMsgActions->setCurrentMessage( item );
4316 }
4317 
4318 void KMMainWidget::itemsFetchDone( KJob *job )
4319 {
4320  delete mShowBusySplashTimer;
4321  mShowBusySplashTimer = 0;
4322  if ( job->error() ) {
4323  // Unfortunately job->error() is Job::Unknown in many cases.
4324  // (see JobPrivate::handleResponse in akonadi/job.cpp)
4325  // So we show the "offline" page after checking the resource status.
4326  kDebug() << job->error() << job->errorString();
4327 
4328  const QString resource = job->property("_resource").toString();
4329  const Akonadi::AgentInstance agentInstance = Akonadi::AgentManager::self()->instance( resource );
4330  if ( !agentInstance.isOnline() ) {
4331  // The resource is offline
4332  if ( mMsgView ) {
4333  mMsgView->viewer()->enableMessageDisplay();
4334  mMsgView->clear( true );
4335  }
4336  mMessagePane->show();
4337 
4338  if (kmkernel->isOffline())
4339  showOfflinePage();
4340  else
4341  showResourceOfflinePage();
4342  } else {
4343  // Some other error
4344  BroadcastStatus::instance()->setStatusMsg( job->errorString() );
4345  }
4346  }
4347 }
4348 
4349 KAction *KMMainWidget::akonadiStandardAction( Akonadi::StandardActionManager::Type type )
4350 {
4351  return mAkonadiStandardActionManager->action( type );
4352 }
4353 
4354 KAction *KMMainWidget::akonadiStandardAction( Akonadi::StandardMailActionManager::Type type )
4355 {
4356  return mAkonadiStandardActionManager->action( type );
4357 }
4358 
4359 void KMMainWidget::slotRemoveDuplicates()
4360 {
4361  RemoveDuplicateMailJob *job = new RemoveDuplicateMailJob(mFolderTreeWidget->folderTreeView()->selectionModel(), this, this);
4362  job->start();
4363 }
4364 
4365 void KMMainWidget::slotServerSideSubscription()
4366 {
4367  if ( !mCurrentFolder )
4368  return;
4369  ManageServerSideSubscriptionJob *job = new ManageServerSideSubscriptionJob(this);
4370  job->setCurrentFolder(mCurrentFolder);
4371  job->setParentWidget(this);
4372  job->start();
4373 }
4374 
4375 void KMMainWidget::savePaneSelection()
4376 {
4377  if (mMessagePane) {
4378  mMessagePane->saveCurrentSelection();
4379  }
4380 }
4381 
4382 void KMMainWidget::updatePaneTagComboBox()
4383 {
4384  if (mMessagePane) {
4385  mMessagePane->updateTagComboBox();
4386  }
4387 }
4388 
4389 void KMMainWidget::slotCreateAddressBookContact()
4390 {
4391  CreateNewContactJob *job = new CreateNewContactJob( this, this );
4392  job->start();
4393 }
4394 
4395 void KMMainWidget::slotOpenRecentMsg(const KUrl& url)
4396 {
4397  KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( this, url, overrideEncoding(), this );
4398  openCommand->start();
4399 }
4400 
4401 void KMMainWidget::addRecentFile(const KUrl& mUrl)
4402 {
4403  mOpenRecentAction->addUrl(mUrl);
4404  KConfigGroup grp = mConfig->group(QLatin1String("Recent Files"));
4405  mOpenRecentAction->saveEntries(grp);
4406  grp.sync();
4407 }
4408 
4409 void KMMainWidget::slotMoveMessageToTrash()
4410 {
4411  if (messageView() && messageView()->viewer()) {
4412  KMTrashMsgCommand *command = new KMTrashMsgCommand( mCurrentFolder->collection(), messageView()->viewer()->messageItem(), -1 );
4413  command->start();
4414  }
4415 }
4416 
4417 void KMMainWidget::slotArchiveMails()
4418 {
4419  const QList<Akonadi::Item> selectedMessages = mMessagePane->selectionAsMessageItemList();
4420  KMKernel::self()->folderArchiveManager()->setArchiveItems(selectedMessages, mCurrentFolder->collection().resource());
4421 }
4422 
4423 void KMMainWidget::updateQuickSearchLineText()
4424 {
4425  //If change change shortcut
4426  mMessagePane->setQuickSearchClickMessage(i18nc("Show shortcut for focus quick search. Don't change it", "Search...<%1>",mQuickSearchAction->shortcut().toString()));
4427 }
4428 
4429 void KMMainWidget::slotChangeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage format)
4430 {
4431  if (format == MessageViewer::Viewer::Html) {
4432  const int result = KMessageBox::warningContinueCancel( this,
4433  // the warning text is taken from configuredialog.cpp:
4434  i18n( "Use of HTML in mail will make you more vulnerable to "
4435  "\"spam\" and may increase the likelihood that your system will be "
4436  "compromised by other present and anticipated security exploits." ),
4437  i18n( "Security Warning" ),
4438  KGuiItem(i18n( "Use HTML" )),
4439  KStandardGuiItem::cancel(),
4440  QLatin1String("OverrideHtmlWarning"), 0);
4441  if ( result == KMessageBox::Cancel ) {
4442  mDisplayMessageFormatMenu->setDisplayMessageFormat(MessageViewer::Viewer::Text);
4443  return;
4444  }
4445  }
4446  mFolderDisplayFormatPreference = format;
4447 
4448  //Update mPrefererHtmlLoadExtAction
4449  const bool useHtml = (mFolderDisplayFormatPreference == MessageViewer::Viewer::Html || (mHtmlGlobalSetting && mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting));
4450  mPreferHtmlLoadExtAction->setEnabled( useHtml );
4451 
4452  if (mMsgView) {
4453  mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
4454  mMsgView->update( true );
4455  }
4456 }
4457 
4458 void KMMainWidget::populateMessageListStatusFilterCombo()
4459 {
4460  mMessagePane->populateStatusFilterCombo();
4461 }
4462 
4463 void KMMainWidget::slotCollectionRemoved(const Akonadi::Collection &col)
4464 {
4465  if (mFavoritesModel)
4466  mFavoritesModel->removeCollection(col);
4467 }
KMMainWidget::readPreConfig
void readPreConfig()
Read configuration options before widgets are created.
Definition: kmmainwidget.cpp:542
QAction::setText
void setText(const QString &text)
KMMainWidget::slotConfigChanged
void slotConfigChanged()
Definition: kmmainwidget.cpp:2209
QList::clear
void clear()
KMReplyCommand
Definition: kmcommands.h:319
QModelIndex
KMMainWidget::slotUpdateUndo
void slotUpdateUndo()
Update the undo action.
Definition: kmmainwidget.cpp:4050
KMMainWidget::slotCreateAddressBookContact
void slotCreateAddressBookContact()
Definition: kmmainwidget.cpp:4389
ManageServerSideSubscriptionJob
Definition: manageserversidesubscriptionjob.h:25
globalsettings.h
QWidget
KMMainWidget::slotCollectionChanged
void slotCollectionChanged(const Akonadi::Collection &, const QSet< QByteArray > &)
Definition: kmmainwidget.cpp:1203
QApplication::isRightToLeft
bool isRightToLeft()
kactionmenuaccount.h
KMMainWidget::slotSetThreadStatusUnread
void slotSetThreadStatusUnread()
Definition: kmmainwidget.cpp:1963
collectionshortcutpage.h
antispamwizard.h
KMReaderMainWin::showMessage
void showMessage(const QString &encoding, const Akonadi::Item &msg, const Akonadi::Collection &parentCollection=Akonadi::Collection())
take ownership of and show
Definition: kmreadermainwin.cpp:136
KMMainWidget::slotItemAdded
void slotItemAdded(const Akonadi::Item &, const Akonadi::Collection &col)
Definition: kmmainwidget.cpp:1224
KMFetchMessageCommand
Definition: kmcommands.h:588
KMail::Util::mailingListPost
bool mailingListPost(const QSharedPointer< MailCommon::FolderCollection > &fd)
Definition: util.cpp:150
KMMainWidget::slotToFilter
void slotToFilter()
Definition: kmmainwidget.cpp:2103
kmmainwidget.h
KMMainWidget::slotManageSieveScripts
void slotManageSieveScripts()
Definition: kmmainwidget.cpp:1289
KXMLGUIClient
KMMainWidget::akonadiStandardAction
KAction * akonadiStandardAction(Akonadi::StandardActionManager::Type type)
Definition: kmmainwidget.cpp:4349
KMMainWidget::slotExpandAllThreads
void slotExpandAllThreads()
Definition: kmmainwidget.cpp:3571
KMMainWidget::slotItemsFetchedForActivation
void slotItemsFetchedForActivation(KMCommand *command)
Definition: kmmainwidget.cpp:2539
KMMainWidget::slotSetThreadStatusWatched
void slotSetThreadStatusWatched()
Definition: kmmainwidget.cpp:1983
QByteArray
KMReaderWin
This class implements a "reader window", that is a window used for reading or viewing messages...
Definition: kmreaderwin.h:49
KMTrashMsgCommand
Definition: kmcommands.h:552
KMail::KMKnotify
Definition: kmknotify.h:37
KMMainWidget::slotUseTemplate
void slotUseTemplate()
Definition: kmmainwidget.cpp:1636
KMMainWidget::slotDelayedShowNewFromTemplate
void slotDelayedShowNewFromTemplate(KJob *)
Definition: kmmainwidget.cpp:1374
KMMainWidget::slotReplaceMsgByUnencryptedVersion
void slotReplaceMsgByUnencryptedVersion()
Definition: kmmainwidget.cpp:2328
KMMainWidget::slotSetThreadStatusImportant
void slotSetThreadStatusImportant()
Definition: kmmainwidget.cpp:1968
text
virtual QByteArray text(quint32 serialNumber) const =0
KMMainWidget::layoutSplitters
void layoutSplitters()
Definition: kmmainwidget.cpp:597
vacationscriptindicatorwidget.h
KMMainWidget::slotCheckMail
void slotCheckMail()
Definition: kmmainwidget.cpp:1302
email
const QString email
Definition: identitydialog.cpp:640
tagactionmanager.h
QAction::data
QVariant data() const
KMMainWidget::slotFromFilter
void slotFromFilter()
Definition: kmmainwidget.cpp:2089
KMUseTemplateCommand
Definition: kmcommands.h:250
KMSetTagCommand
This command is used to set or toggle a tag for a list of messages.
Definition: kmcommands.h:436
folderarchivemanager.h
QProcess::startDetached
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
KMail::MessageActions
Manages common actions that can be performed on one or more messages.
Definition: messageactions.h:50
KMMainWidget::slotMessagePopup
void slotMessagePopup(const Akonadi::Item &, const KUrl &, const KUrl &imageUrl, const QPoint &)
Definition: kmmainwidget.cpp:2586
QMenu::addAction
void addAction(QAction *action)
QPointer< MailCommon::FolderSelectionDialog >
KMMainWidget::~KMMainWidget
virtual ~KMMainWidget()
Definition: kmmainwidget.cpp:373
collectionmailinglistpage.h
KMMainWidget::slotMessageSelected
void slotMessageSelected(const Akonadi::Item &)
Opens mail in the internal viewer.
Definition: kmmainwidget.cpp:4255
KMKernel::folderArchiveManager
FolderArchiveManager * folderArchiveManager() const
Definition: kmkernel.cpp:2075
KMMainWidget::slotOverrideHtmlLoadExt
void slotOverrideHtmlLoadExt()
Definition: kmmainwidget.cpp:1564
KMMainWidget::slotSetThreadStatusToAct
void slotSetThreadStatusToAct()
Definition: kmmainwidget.cpp:1978
KMMainWidget::slotCompose
void slotCompose()
Definition: kmmainwidget.cpp:1314
KMMainWidget::slotFocusQuickSearch
void slotFocusQuickSearch()
Definition: kmmainwidget.cpp:1250
KMMoveCommand
Definition: kmcommands.h:523
QVariant::value
T value() const
KMMainWidget::slotMessageActivated
void slotMessageActivated(const Akonadi::Item &)
Open a separate viewer window containing the specified message.
Definition: kmmainwidget.cpp:2515
kmknotify.h
KMMainWidget::slotCustomReplyAllToMsg
void slotCustomReplyAllToMsg(const QString &tmpl)
Definition: kmmainwidget.cpp:2030
KMMainWidget::slotFilter
void slotFilter()
Definition: kmmainwidget.cpp:1284
KMMainWidget::writeReaderConfig
void writeReaderConfig()
Definition: kmmainwidget.cpp:929
ManageServerSideSubscriptionJob::start
void start()
Definition: manageserversidesubscriptionjob.cpp:40
removeduplicatemailjob.h
KMMainWidget::refreshMessageListSelection
void refreshMessageListSelection()
Definition: kmmainwidget.cpp:1936
KMMainWidget::slotEmptyFolder
void slotEmptyFolder()
Definition: kmmainwidget.cpp:1477
removecollectionjob.h
QPoint
kmmainwin.h
undostack.h
RemoveCollectionJob::start
void start()
Definition: removecollectionjob.cpp:50
KMMainWidget::copySelectedMessagesToFolder
void copySelectedMessagesToFolder(const Akonadi::Collection &dest)
Definition: kmmainwidget.cpp:1832
KMMainWidget::currentFolder
QSharedPointer< MailCommon::FolderCollection > currentFolder() const
Definition: kmmainwidget.cpp:4161
KMMainWidget::slotExpireFolder
void slotExpireFolder()
Definition: kmmainwidget.cpp:1437
KMMainWidget::slotShowStartupFolder
void slotShowStartupFolder()
Definition: kmmainwidget.cpp:4005
from
QString from() const
KMMainWidget::slotSelectMoreMessageTagList
void slotSelectMoreMessageTagList()
Definition: kmmainwidget.cpp:1911
KMMainWidget::slotShowNewFromTemplate
void slotShowNewFromTemplate()
Definition: kmmainwidget.cpp:1352
KMMainWidget::slotDeleteThread
void slotDeleteThread(bool confirmDelete=true)
Definition: kmmainwidget.cpp:1737
manageshowcollectionproperties.h
collectionmaintenancepage.h
KMMainWidget::slotDebugSieve
void slotDebugSieve()
Definition: kmmainwidget.cpp:2196
KMail::Composer
Definition: composer.h:39
KMMainWidget::destruct
void destruct()
Definition: kmmainwidget.cpp:383
KMKernel::self
static KMKernel * self()
normal control stuff
Definition: kmkernel.cpp:1471
searchwindow.h
KMCommand::result
Result result() const
Returns the result of the command.
Definition: kmcommands.cpp:206
KMMoveCommand::destFolder
Akonadi::Collection destFolder() const
Definition: kmcommands.h:530
KMMainWidget::slotClearCurrentFolder
void slotClearCurrentFolder()
Definition: kmmainwidget.cpp:1542
QList::size
int size() const
KMKernel::config
KSharedConfig::Ptr config()
Definition: kmkernel.cpp:1476
KMail::TagActionManager
Creates actions related to the existing Akonadi tags and plugs them into the GUI. ...
Definition: tagactionmanager.h:55
KMMainWidget::deleteWidgets
void deleteWidgets()
Definition: kmmainwidget.cpp:939
KMMainWidget::slotExtendSelectionToPreviousMessage
void slotExtendSelectionToPreviousMessage()
Definition: kmmainwidget.cpp:2476
KMMainWidget::updateFileMenu
void updateFileMenu()
Definition: kmmainwidget.cpp:4143
KActionMenuTransport
Definition: kactionmenutransport.h:27
folderarchiveutil.h
KMSetTagCommand::Toggle
Definition: kmcommands.h:441
createnewcontactjob.h
KMMainWidget::showEvent
virtual void showEvent(QShowEvent *event)
Definition: kmmainwidget.cpp:4175
KMMainWidget::slotJumpToFolder
void slotJumpToFolder()
Definition: kmmainwidget.cpp:2121
TagSelectDialog
Definition: tagselectdialog.h:39
KMMainWidget::slotFocusOnPrevMessage
void slotFocusOnPrevMessage()
Definition: kmmainwidget.cpp:2400
FolderArchiveManager::setArchiveItems
void setArchiveItems(const QList< Akonadi::Item > &items, const QString &instanceName)
Definition: folderarchivemanager.cpp:122
QModelIndex::isValid
bool isValid() const
KMMetaFilterActionCommand
Definition: kmcommands.h:476
KMMainWidget::slotEditVacation
void slotEditVacation(const QString &serverName=QString())
Trigger the dialog for editing out-of-office scripts.
Definition: kmmainwidget.cpp:2186
KMMainWidget::vacationScriptIndicator
QWidget * vacationScriptIndicator() const
Definition: kmmainwidget.cpp:4235
KMSaveAttachmentsCommand
Definition: kmcommands.h:298
QBoxLayout::addWidget
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
QWidget::showEvent
virtual void showEvent(QShowEvent *event)
QList::count
int count(const T &value) const
KMMainWidget::slotUpdateOnlineStatus
void slotUpdateOnlineStatus(GlobalSettings::EnumNetworkState::type)
Definition: kmmainwidget.cpp:2270
QList::append
void append(const T &value)
KMMainWidget::startUpdateMessageActionsTimer
void startUpdateMessageActionsTimer()
Start a timer to update message actions.
Definition: kmmainwidget.cpp:3595
KMMainWidget::slotSendQueuedVia
void slotSendQueuedVia(MailTransport::Transport *transport)
Definition: kmmainwidget.cpp:2295
tagselectdialog.h
KMMainWidget::slotSubjectFilter
void slotSubjectFilter()
Definition: kmmainwidget.cpp:2079
KMMainWidget::slotMessageStatusChangeRequest
void slotMessageStatusChangeRequest(const Akonadi::Item &, const Akonadi::MessageStatus &, const Akonadi::MessageStatus &)
Definition: kmmainwidget.cpp:2561
KMMainWidget::readConfig
void readConfig()
Read configuration options after widgets are created.
Definition: kmmainwidget.cpp:802
KMMainWidget::slotStartCheckMail
void slotStartCheckMail()
Definition: kmmainwidget.cpp:406
KMCommand
Small helper structure which encapsulates the KMMessage created when creating a reply, and.
Definition: kmcommands.h:48
QTimer
KMMainWidget::slotShowSelectedFolderInPane
void slotShowSelectedFolderInPane()
Definition: kmmainwidget.cpp:526
kactionmenutransport.h
QSharedPointer
Definition: collectionmailinglistpage.h:34
KPIM::ProgressManager
KMMainWidget::slotArchiveFolder
void slotArchiveFolder()
Definition: kmmainwidget.cpp:1518
RemoveCollectionJob::setMainWidget
void setMainWidget(KMMainWidget *mainWidget)
Definition: removecollectionjob.cpp:40
KMMainWidget::updateFolderMenu
void updateFolderMenu()
Update html and threaded messages preferences in Folder menu.
Definition: kmmainwidget.cpp:3918
KMMainWidget::restoreCollectionFolderViewConfig
void restoreCollectionFolderViewConfig()
Definition: kmmainwidget.cpp:344
KMMainWidget::slotCheckMailOnStartup
void slotCheckMailOnStartup()
Definition: kmmainwidget.cpp:1308
KMMainWidget::slotSelectNextMessage
void slotSelectNextMessage()
Message navigation.
Definition: kmmainwidget.cpp:2420
RemoveCollectionJob::setCurrentFolder
void setCurrentFolder(const Akonadi::Collection &currentFolder)
Definition: removecollectionjob.cpp:45
KMMainWidget::slotSelectPreviousUnreadMessage
void slotSelectPreviousUnreadMessage()
Definition: kmmainwidget.cpp:2486
QShowEvent
KMMainWidget::slotAkonadiStandardActionUpdated
void slotAkonadiStandardActionUpdated()
Definition: kmmainwidget.cpp:3802
KMMainWidget::moveSelectedMessagesToFolder
void moveSelectedMessagesToFolder(const Akonadi::Collection &dest)
Definition: kmmainwidget.cpp:1779
KMMoveCommand::refSet
MessageList::Core::MessageItemSetReference refSet() const
Definition: kmcommands.h:532
KMMainWidget::slotDeleteMsg
void slotDeleteMsg(bool confirmDelete=true)
Definition: kmmainwidget.cpp:1729
KMMainWidget::slotShowBusySplash
void slotShowBusySplash()
Show a splash screen for the longer-lasting operation.
Definition: kmmainwidget.cpp:2305
KMMainWidget::slotItemMoved
void slotItemMoved(const Akonadi::Item &item, const Akonadi::Collection &from, const Akonadi::Collection &to)
Definition: kmmainwidget.cpp:1241
QList::isEmpty
bool isEmpty() const
KMMainWidget::slotCreateNewTab
void slotCreateNewTab(bool)
Definition: kmmainwidget.cpp:1198
QObject::setObjectName
void setObjectName(const QString &name)
KMMainWidget::slotSendQueued
void slotSendQueued()
Definition: kmmainwidget.cpp:2287
KMMainWidget::updatePaneTagComboBox
void updatePaneTagComboBox()
Definition: kmmainwidget.cpp:4382
QString::isEmpty
bool isEmpty() const
KMail::AntiSpamWizard
KMail anti-spam wizard.
Definition: antispamwizard.h:104
progressmanager.h
collectionpane.h
KMCommand::start
void start()
Definition: kmcommands.cpp:233
KMMainWidget::slotTrashThread
void slotTrashThread()
Definition: kmmainwidget.cpp:1890
RemoveDuplicateMailJob
Definition: removeduplicatemailjob.h:27
to
QString to() const
KMail::ArchiveFolderDialog
Definition: archivefolderdialog.h:41
KMMainWidget::slotRedirectMsg
void slotRedirectMsg()
Definition: kmmainwidget.cpp:1998
kmsystemtray.h
QVBoxLayout
collectionviewpage.h
KMMainWidget::savePaneSelection
void savePaneSelection()
Definition: kmmainwidget.cpp:4375
KMMainWidget::slotEndCheckMail
void slotEndCheckMail()
Definition: kmmainwidget.cpp:412
KMMainWidget
Definition: kmmainwidget.h:91
KMMainWidget::newFromTemplate
void newFromTemplate(const Akonadi::Item &)
Definition: kmmainwidget.cpp:1416
QSet
KMMainWidget::slotApplyFilters
void slotApplyFilters()
Definition: kmmainwidget.cpp:2141
ManageServerSideSubscriptionJob::setParentWidget
void setParentWidget(QWidget *parentWidget)
Definition: manageserversidesubscriptionjob.cpp:79
QList::first
T & first()
KMMainWidget::slotPrevUnreadFolder
void slotPrevUnreadFolder()
Definition: kmmainwidget.cpp:3552
KMMainWidget::slotItemRemoved
void slotItemRemoved(const Akonadi::Item &)
Definition: kmmainwidget.cpp:1234
KMMainWidget::slotAddFavoriteFolder
void slotAddFavoriteFolder()
Definition: kmmainwidget.cpp:3510
QMenu::addSeparator
QAction * addSeparator()
KMMainWidget::slotSelectPreviousMessage
void slotSelectPreviousMessage()
Definition: kmmainwidget.cpp:2469
KMMainWidget::slotExtendSelectionToNextMessage
void slotExtendSelectionToNextMessage()
Definition: kmmainwidget.cpp:2427
QString
QList
KMMainWidget::slotRemoveFolder
void slotRemoveFolder()
Definition: kmmainwidget.cpp:1528
KMMainWidget::showResourceOfflinePage
void showResourceOfflinePage()
Definition: kmmainwidget.cpp:2319
util.h
KMail::ArchiveFolderDialog::setFolder
void setFolder(const Akonadi::Collection &defaultCollection)
Definition: archivefolderdialog.cpp:161
QLayout::setMargin
void setMargin(int margin)
KMMainWidget::slotMoveSelectedMessageToFolder
void slotMoveSelectedMessageToFolder()
This will ask for a destination folder and move the currently selected messages (in MessageListView) ...
Definition: kmmainwidget.cpp:1767
kmkernel
#define kmkernel
Definition: kmkernel.h:24
KActionMenuAccount
Definition: kactionmenuaccount.h:23
KMMainWidget::slotExpandThread
void slotExpandThread()
Definition: kmmainwidget.cpp:3561
KMMainWidget::slotSaveAttachments
void slotSaveAttachments()
Definition: kmmainwidget.cpp:2235
collectionquotapage.h
QByteArray::append
QByteArray & append(char ch)
KMCommand::OK
Definition: kmcommands.h:53
QAction::setData
void setData(const QVariant &userData)
KMMainWidget::mainWidgetList
static const PtrList * mainWidgetList()
Returns a list of all KMMainWidgets.
Definition: kmmainwidget.cpp:4151
KMMainWidget::initializeFilterActions
void initializeFilterActions()
Definition: kmmainwidget.cpp:4087
KMForwardAttachedCommand
Definition: kmcommands.h:355
kmlaunchexternalcomponent.h
ManageShowCollectionProperties
Definition: manageshowcollectionproperties.h:33
KMOpenMsgCommand
Definition: kmcommands.h:273
KMMainWidget::folderShortcutActionManager
KMail::FolderShortcutActionManager * folderShortcutActionManager() const
Definition: kmmainwidget.cpp:4250
QLatin1Char
KMMainWidget::slotTrashSelectedMessages
void slotTrashSelectedMessages()
Implements the "move to trash" action.
Definition: kmmainwidget.cpp:1882
TagSelectDialog::setActionCollection
void setActionCollection(const QList< KActionCollection * > &actionCollectionList)
Definition: tagselectdialog.cpp:121
KMMainWidget::slotSelectFocusedMessage
void slotSelectFocusedMessage()
Definition: kmmainwidget.cpp:2415
KMMainWidget::slotForwardInlineMsg
void slotForwardInlineMsg()
Definition: kmmainwidget.cpp:1600
QVariant::setValue
void setValue(const T &value)
QVariant::fromValue
QVariant fromValue(const T &value)
CreateNewContactJob
The CreateNewContactJob class The job will check if there is address book folder to store new contact...
Definition: createnewcontactjob.h:32
KMMainWidget::slotSelectCollectionFolder
void slotSelectCollectionFolder(const Akonadi::Collection &col)
Definition: kmmainwidget.cpp:2133
ManageServerSideSubscriptionJob::setCurrentFolder
void setCurrentFolder(const QSharedPointer< MailCommon::FolderCollection > &currentFolder)
Definition: manageserversidesubscriptionjob.cpp:84
KMMainWidget::slotPostToML
void slotPostToML()
Definition: kmmainwidget.cpp:1426
KMLaunchExternalComponent
Definition: kmlaunchexternalcomponent.h:23
QSet::contains
bool contains(const T &value) const
KMSetTagCommand::CleanExistingAndAddNew
Definition: kmcommands.h:441
KMMainWidget::readFolderConfig
void readFolderConfig()
Read configuration for current folder.
Definition: kmmainwidget.cpp:563
archivefolderdialog.h
KMMainWidget::slotOpenMsg
void slotOpenMsg()
Definition: kmmainwidget.cpp:2227
KMReaderWin::newFeaturesMD5
static QString newFeaturesMD5()
Returns the MD5 hash for the list of new features.
Definition: kmreaderwin.cpp:325
KMMainWidget::writeConfig
void writeConfig(bool force=true)
Write configuration options.
Definition: kmmainwidget.cpp:872
KMForwardCommand
Definition: kmcommands.h:336
set
void set(quint32, const QString &, const QString &, const QString &, const QString &, time_t)
QItemSelection
KMMainWidget::slotSaveMsg
void slotSaveMsg()
Definition: kmmainwidget.cpp:2217
QString::replace
QString & replace(int position, int n, QChar after)
KMMainWidget::actionCollections
QList< KActionCollection * > actionCollections() const
Convenience function to get the action collection in a list.
Definition: kmmainwidget.cpp:4045
QSplitter
FolderArchive::FolderArchiveUtil::resourceSupportArchiving
bool resourceSupportArchiving(const QString &resource)
Definition: folderarchiveutil.cpp:35
GlobalSettings::self
static GlobalSettings * self()
Definition: globalsettings.cpp:30
KActionMenu
KMMainWidget::slotForwardAttachedMsg
void slotForwardAttachedMsg()
Definition: kmmainwidget.cpp:1618
KMMainWidget::showOfflinePage
void showOfflinePage()
Show a message screen explaining that we are currently offline, when an online folder is selected...
Definition: kmmainwidget.cpp:2312
KMMainWidget::slotSetThreadStatusIgnored
void slotSetThreadStatusIgnored()
Definition: kmmainwidget.cpp:1990
KMMainWidget::updateMessageActions
void updateMessageActions(bool fast=false)
Update message actions.
Definition: kmmainwidget.cpp:3605
KPIM::BroadcastStatus
KMMainWidget::slotReadOn
void slotReadOn()
Definition: kmmainwidget.cpp:3532
KMMainWidget::slotResendMsg
void slotResendMsg()
Definition: kmmainwidget.cpp:1643
KMMainWidget::slotCollapseAllThreads
void slotCollapseAllThreads()
Definition: kmmainwidget.cpp:3580
KMMainWidget::slotCheckVacation
void slotCheckVacation()
Definition: kmmainwidget.cpp:2175
QModelIndex::data
QVariant data(int role) const
KMMainWidget::slotHelp
void slotHelp()
Definition: kmmainwidget.cpp:1277
KMMainWidget::slotOnlineStatus
void slotOnlineStatus()
Definition: kmmainwidget.cpp:2257
KMMainWidget::slotContactSearchJobForMessagePopupDone
void slotContactSearchJobForMessagePopupDone(KJob *job)
Definition: kmmainwidget.cpp:2605
QLatin1String
QKeySequence
KMSetStatusCommand
Definition: kmcommands.h:415
KMMainWidget::slotUpdateActionsAfterMailChecking
void slotUpdateActionsAfterMailChecking()
Definition: kmmainwidget.cpp:418
Qt::escape
QString escape(const QString &plain)
foldershortcutactionmanager.h
composer.h
KMMainWidget::slotCopySelectedMessagesToFolder
void slotCopySelectedMessagesToFolder()
This will ask for a destination folder and copy the currently selected messages (in MessageListView) ...
Definition: kmmainwidget.cpp:1819
QAction
KMMainWidget::clearViewer
void clearViewer()
Definition: kmmainwidget.cpp:533
KMMainWidget::folderSelected
void folderSelected(const Akonadi::Collection &col)
Select the given folder If the folder is 0 the intro is shown.
Definition: kmmainwidget.cpp:457
KMMainWidget::slotMessageQueuedOrDrafted
void slotMessageQueuedOrDrafted()
Definition: kmmainwidget.cpp:1590
KMMainWidget::clearFilterActions
void clearFilterActions()
Clear and create actions for marked filters.
Definition: kmmainwidget.cpp:4065
KMReaderMainWin
Definition: kmreadermainwin.h:34
RemoveCollectionJob
Definition: removecollectionjob.h:25
KMMainWidget::updateVacationScriptStatus
void updateVacationScriptStatus()
Definition: kmmainwidget.cpp:4240
KMFetchMessageCommand::item
Akonadi::Item item() const
Definition: kmcommands.cpp:1646
KMail::FolderShortcutActionManager
Definition: foldershortcutactionmanager.h:61
KMMainWidget::tagActionManager
KMail::TagActionManager * tagActionManager() const
Definition: kmmainwidget.cpp:4245
KMCommand::Failed
Definition: kmcommands.h:53
KMMainWidget::slotSetThreadStatusRead
void slotSetThreadStatusRead()
Definition: kmmainwidget.cpp:1973
KMMainWidget::updateMessageActionsDelayed
void updateMessageActionsDelayed()
Definition: kmmainwidget.cpp:3625
KMail::Composer::setFocusToEditor
virtual void setFocusToEditor()=0
Sets the focus to the edit-widget and the cursor below the "On ... you wrote" line when hasMessage is...
KMMainWidget::slotCustomReplyToMsg
void slotCustomReplyToMsg(const QString &tmpl)
Slot to reply to a message.
Definition: kmmainwidget.cpp:2010
QString::fromLatin1
QString fromLatin1(const char *str, int size)
displaymessageformatactionmenu.h
CollectionPane
Definition: collectionpane.h:25
KMMainWidget::slotFocusOnNextMessage
void slotFocusOnNextMessage()
Definition: kmmainwidget.cpp:2395
manageserversidesubscriptionjob.h
KMMainWidget::slotSelectLastMessage
void slotSelectLastMessage()
Definition: kmmainwidget.cpp:2410
KMMainWidget::slotUndo
void slotUndo()
Definition: kmmainwidget.cpp:2112
KMMainWidget::slotCollapseThread
void slotCollapseThread()
Definition: kmmainwidget.cpp:3566
KMMainWidget::slotSearch
bool slotSearch()
Definition: kmmainwidget.cpp:1257
KMMainWidget::addRecentFile
void addRecentFile(const KUrl &mUrl)
Definition: kmmainwidget.cpp:4401
KMMainWidget::slotApplyFiltersOnFolder
void slotApplyFiltersOnFolder()
Definition: kmmainwidget.cpp:2149
KMMainWidget::populateMessageListStatusFilterCombo
void populateMessageListStatusFilterCombo()
Definition: kmmainwidget.cpp:4458
KMail::Composer::New
Definition: composer.h:46
kmreadermainwin.h
CreateNewContactJob::start
void start()
start the job
Definition: createnewcontactjob.cpp:49
KMReaderMainWin::setUseFixedFont
void setUseFixedFont(bool useFixedFont)
Definition: kmreadermainwin.cpp:131
kmcommands.h
KMMainWidget::slotDisplayCurrentMessage
void slotDisplayCurrentMessage()
etc.
Definition: kmmainwidget.cpp:2508
collectiontemplatespage.h
KMMainWidget::createWidgets
void createWidgets()
Definition: kmmainwidget.cpp:958
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KMail::Composer::setCollectionForNewMessage
virtual void setCollectionForNewMessage(const Akonadi::Collection &folder)=0
QAction::menu
QMenu * menu() const
KMMainWidget::slotMarkAll
void slotMarkAll()
Definition: kmmainwidget.cpp:2580
KMMainWidget::slotEditNotifications
void slotEditNotifications()
Settings menu.
Definition: kmmainwidget.cpp:3525
KMSaveMsgCommand
Definition: kmcommands.h:261
KMMainWidget::writeFolderConfig
void writeFolderConfig()
Write configuration for current folder.
Definition: kmmainwidget.cpp:583
KMResendMessageCommand
Definition: kmcommands.h:565
broadcaststatus.h
KMMainWidget::slotSelectFirstMessage
void slotSelectFirstMessage()
Definition: kmmainwidget.cpp:2405
RemoveDuplicateMailJob::start
void start()
Definition: removeduplicatemailjob.cpp:45
KMMainWidget::setupActions
void setupActions()
Definition: kmmainwidget.cpp:2779
KMRedirectCommand
Definition: kmcommands.h:372
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QVariant::toString
QString toString() const
KMMainWidget::slotCustomForwardMsg
void slotCustomForwardMsg(const QString &tmpl)
Definition: kmmainwidget.cpp:2053
KMCommand::Result
Result
Definition: kmcommands.h:53
KMMainWidget::slotUpdateMessageTagList
void slotUpdateMessageTagList(const Akonadi::Tag &tag)
Adds if not existing/removes if existing the tag identified by aLabel in all selected messages...
Definition: kmmainwidget.cpp:1927
KMMainWidget::slotOpenRecentMsg
void slotOpenRecentMsg(const KUrl &url)
Definition: kmmainwidget.cpp:4395
KJob
KMMainWidget::updateQuickSearchLineText
void updateQuickSearchLineText()
Definition: kmmainwidget.cpp:4423
KMMainWidget::slotExpireAll
void slotExpireAll()
Definition: kmmainwidget.cpp:1548
KMMainWidget::slotCollectionStatisticsChanged
void slotCollectionStatisticsChanged(const Akonadi::Collection::Id, const Akonadi::CollectionStatistics &)
Definition: kmmainwidget.cpp:1185
QAction::setEnabled
void setEnabled(bool)
KMail::SearchWindow::activateFolder
void activateFolder(const Akonadi::Collection &folder)
Changes the base folder for search operations to a different folder.
Definition: searchwindow.cpp:382
KMail::VacationScriptIndicatorWidget
Definition: vacationscriptindicatorwidget.h:57
KMMainWidget::slotNewFromTemplate
void slotNewFromTemplate(QAction *)
Definition: kmmainwidget.cpp:1405
QIcon
KMMainWidget::updateMessageMenu
void updateMessageMenu()
Update message menu.
Definition: kmmainwidget.cpp:3590
KMCopyCommand
Definition: kmcommands.h:504
KMail::SearchWindow
Definition: searchwindow.h:63
DisplayMessageFormatActionMenu
Definition: displaymessageformatactionmenu.h:24
KMMainWidget::slotSelectNextUnreadMessage
void slotSelectNextUnreadMessage()
Definition: kmmainwidget.cpp:2437
KMMainWidget::slotRemoveDuplicates
void slotRemoveDuplicates()
Definition: kmmainwidget.cpp:4359
QTimer::singleShot
singleShot
QVariant
KMMainWidget::slotNextUnreadFolder
void slotNextUnreadFolder()
Definition: kmmainwidget.cpp:3543
KMMainWidget::slotIntro
void slotIntro()
Definition: kmmainwidget.cpp:3990
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:34:33 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kmail

Skip menu "kmail"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal