Continue to implement fullsync
[kdepim.git] / kmail / kmmainwidget.cpp
blobe8b159680d4bbc6465f384f7fd2593580085bb90
1 /*
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>
6 Based on the work of Stefan Taferner <taferner@kde.org>
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.
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.
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
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 <TemplateParser/CustomTemplatesMenu>
33 #include "MailCommon/FolderSelectionDialog"
34 #include "MailCommon/FolderTreeWidget"
35 #include "util.h"
36 #include "mailcommon/mailutil.h"
37 #include "mailcommon/mailkernel.h"
38 #include "dialog/archivefolderdialog.h"
39 #include "settings/kmailsettings.h"
40 #include "MailCommon/FolderTreeView"
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 "mailcommon/searchrulestatus.h"
48 #include "PimCommon/NetworkUtil"
49 #include "kpimtextedit/texttospeech.h"
50 #if !defined(NDEBUG)
51 #include <ksieveui/sievedebugdialog.h>
52 using KSieveUi::SieveDebugDialog;
53 #endif
55 #include "collectionpage/collectionmaintenancepage.h"
56 #include "collectionpage/collectionquotapage.h"
57 #include "collectionpage/collectiontemplatespage.h"
58 #include "collectionpage/collectionshortcutpage.h"
59 #include "collectionpage/collectionviewpage.h"
60 #include "collectionpage/collectionmailinglistpage.h"
61 #include "tag/tagselectdialog.h"
62 #include "job/createnewcontactjob.h"
63 #include "folderarchive/folderarchiveutil.h"
64 #include "folderarchive/folderarchivemanager.h"
66 #include "PimCommon/CollectionAclPage"
67 #include "PimCommon/PimUtil"
68 #include "MailCommon/CollectionGeneralPage"
69 #include "MailCommon/CollectionExpiryPage"
70 #include "MailCommon/ExpireCollectionAttribute"
71 #include "MailCommon/FilterManager"
72 #include "MailCommon/MailFilter"
73 #include "MailCommon/FavoriteCollectionWidget"
74 #include "MailCommon/FolderTreeWidget"
75 #include "MailCommon/FolderTreeView"
76 #include "mailcommonsettings_base.h"
77 #include "kmmainwidget.h"
79 // Other PIM includes
80 #include "kdepim-version.h"
82 #include "messageviewer/messageviewersettings.h"
83 #include "messageviewer/viewer.h"
84 #include "messageviewer/attachmentstrategy.h"
85 #ifndef QT_NO_CURSOR
86 #include "Libkdepim/KCursorSaver"
87 #endif
89 #include "MessageComposer/MessageSender"
90 #include "MessageComposer/MessageHelper"
92 #include "TemplateParser/TemplateParser"
94 #include "MessageCore/MessageCoreSettings"
95 #include "MessageCore/MailingList"
96 #include "messagecore/messagehelpers.h"
98 #include "dialog/kmknotify.h"
99 #include "widgets/displaymessageformatactionmenu.h"
101 #include "ksieveui/vacationmanager.h"
102 #include "kmlaunchexternalcomponent.h"
104 // LIBKDEPIM includes
105 #include "libkdepim/progressmanager.h"
106 #include "libkdepim/broadcaststatus.h"
108 // KDEPIMLIBS includes
109 #include <AkonadiCore/AgentManager>
110 #include <AkonadiCore/AttributeFactory>
111 #include <AkonadiCore/itemfetchjob.h>
112 #include <AkonadiCore/collectionattributessynchronizationjob.h>
113 #include <AkonadiCore/collectionfetchjob.h>
114 #include <AkonadiCore/collectionfetchscope.h>
115 #include <Akonadi/Contact/ContactSearchJob>
116 #include <AkonadiWidgets/collectionpropertiesdialog.h>
117 #include <AkonadiCore/entitydisplayattribute.h>
118 #include <AkonadiWidgets/entitylistview.h>
119 #include <AkonadiWidgets/etmviewstatesaver.h>
120 #include <AkonadiCore/agentinstance.h>
121 #include <AkonadiCore/agenttype.h>
122 #include <AkonadiCore/changerecorder.h>
123 #include <AkonadiCore/session.h>
124 #include <AkonadiCore/entitytreemodel.h>
125 #include <AkonadiCore/favoritecollectionsmodel.h>
126 #include <AkonadiCore/itemfetchscope.h>
127 #include <AkonadiCore/itemmodifyjob.h>
128 #include <AkonadiWidgets/controlgui.h>
129 #include <AkonadiWidgets/collectiondialog.h>
130 #include <AkonadiCore/collectionstatistics.h>
131 #include <AkonadiCore/EntityMimeTypeFilterModel>
132 #include <Akonadi/KMime/MessageFlags>
133 #include <Akonadi/KMime/RemoveDuplicatesJob>
134 #include <AkonadiCore/CachePolicy>
136 #include <kidentitymanagement/identity.h>
137 #include <kidentitymanagement/identitymanager.h>
138 #include <KEmailAddress>
139 #include <mailtransport/transportmanager.h>
140 #include <mailtransport/transport.h>
141 #include <kmime/kmime_mdn.h>
142 #include <kmime/kmime_header_parsing.h>
143 #include <kmime/kmime_message.h>
144 #include <ksieveui/managesievescriptsdialog.h>
145 #include <ksieveui/util.h>
147 // KDELIBS includes
148 #include <kwindowsystem.h>
149 #include <kmessagebox.h>
150 #include <kactionmenu.h>
151 #include <QMenu>
152 #include <kacceleratormanager.h>
153 #include <kstandardshortcut.h>
154 #include <kcharsets.h>
155 #include "kmail_debug.h"
156 #include <ktip.h>
158 #include <kstandardaction.h>
159 #include <ktoggleaction.h>
160 #include <knotification.h>
161 #include <knotifyconfigwidget.h>
162 #include <kstringhandler.h>
163 #include <kconfiggroup.h>
164 #include <ktoolinvocation.h>
165 #include <kxmlguifactory.h>
166 #include <kxmlguiclient.h>
167 #include <QStatusBar>
168 #include <QAction>
169 #include <ktreewidgetsearchline.h>
170 #include <KRecentFilesAction>
172 // Qt includes
173 #include <QByteArray>
174 #include <QHeaderView>
175 #include <QList>
176 #include <QSplitter>
177 #include <QVBoxLayout>
178 #include <QShortcut>
179 #include <QProcess>
180 #include <QDBusConnection>
181 #include <QTextDocument>
182 #include <QDir>
183 // System includes
184 #include <AkonadiWidgets/standardactionmanager.h>
185 #include <KHelpClient>
186 #include <QStandardPaths>
188 #include "PimCommon/ManageServerSideSubscriptionJob"
189 #include <job/removeduplicatemailjob.h>
190 #include <job/removecollectionjob.h>
192 using namespace KMime;
193 using namespace Akonadi;
194 using namespace MailCommon;
195 using KPIM::ProgressManager;
196 using KPIM::BroadcastStatus;
197 using KMail::SearchWindow;
198 using KMail::AntiSpamWizard;
199 using KMime::Types::AddrSpecList;
200 using MessageViewer::AttachmentStrategy;
202 Q_GLOBAL_STATIC(KMMainWidget::PtrList, theMainWidgetList)
204 //-----------------------------------------------------------------------------
205 KMMainWidget::KMMainWidget(QWidget *parent, KXMLGUIClient *aGUIClient,
206 KActionCollection *actionCollection, KSharedConfig::Ptr config) :
207 QWidget(parent),
208 mMoveMsgToFolderAction(Q_NULLPTR),
209 mCollectionProperties(Q_NULLPTR),
210 mFavoriteCollectionsView(Q_NULLPTR),
211 mMsgView(Q_NULLPTR),
212 mSplitter1(Q_NULLPTR),
213 mSplitter2(Q_NULLPTR),
214 mFolderViewSplitter(Q_NULLPTR),
215 mArchiveFolderAction(Q_NULLPTR),
216 mShowBusySplashTimer(Q_NULLPTR),
217 mMsgActions(Q_NULLPTR),
218 mCurrentFolder(Q_NULLPTR),
219 mVacationIndicatorActive(false),
220 mGoToFirstUnreadMessageInSelectedFolder(false),
221 mDisplayMessageFormatMenu(Q_NULLPTR),
222 mFolderDisplayFormatPreference(MessageViewer::Viewer::UseGlobalSetting),
223 mSearchMessages(Q_NULLPTR),
224 mManageShowCollectionProperties(new ManageShowCollectionProperties(this, this)),
225 mShowIntroductionAction(Q_NULLPTR)
227 mLaunchExternalComponent = new KMLaunchExternalComponent(this, this);
228 // must be the first line of the constructor:
229 mStartupDone = false;
230 mWasEverShown = false;
231 mReaderWindowActive = true;
232 mReaderWindowBelow = true;
233 mFolderHtmlLoadExtPreference = false;
234 mDestructed = false;
235 mActionCollection = actionCollection;
236 mTopLayout = new QVBoxLayout(this);
237 mTopLayout->setMargin(0);
238 mConfig = config;
239 mGUIClient = aGUIClient;
240 mFolderTreeWidget = Q_NULLPTR;
241 mPreferHtmlLoadExtAction = Q_NULLPTR;
242 Akonadi::ControlGui::widgetNeedsAkonadi(this);
243 mFavoritesModel = Q_NULLPTR;
244 mVacationManager = new KSieveUi::VacationManager(this);
246 mToolbarActionSeparator = new QAction(this);
247 mToolbarActionSeparator->setSeparator(true);
249 theMainWidgetList->append(this);
251 readPreConfig();
252 createWidgets();
253 setupActions();
255 readConfig();
257 if (!kmkernel->isOffline()) { //kmail is set to online mode, make sure the agents are also online
258 kmkernel->setAccountStatus(true);
261 QTimer::singleShot(0, this, &KMMainWidget::slotShowStartupFolder);
263 connect(kmkernel, &KMKernel::startCheckMail,
264 this, &KMMainWidget::slotStartCheckMail);
266 connect(kmkernel, &KMKernel::endCheckMail,
267 this, &KMMainWidget::slotEndCheckMail);
269 connect(kmkernel, &KMKernel::configChanged,
270 this, &KMMainWidget::slotConfigChanged);
272 connect(kmkernel, &KMKernel::onlineStatusChanged,
273 this, &KMMainWidget::slotUpdateOnlineStatus);
275 connect(mTagActionManager, &KMail::TagActionManager::tagActionTriggered,
276 this, &KMMainWidget::slotUpdateMessageTagList);
278 connect(mTagActionManager, &KMail::TagActionManager::tagMoreActionClicked,
279 this, &KMMainWidget::slotSelectMoreMessageTagList);
281 kmkernel->toggleSystemTray();
284 // make sure the pages are registered only once, since there can be multiple instances of KMMainWidget
285 static bool pagesRegistered = false;
287 if (!pagesRegistered) {
288 Akonadi::CollectionPropertiesDialog::registerPage(new PimCommon::CollectionAclPageFactory);
289 Akonadi::CollectionPropertiesDialog::registerPage(new MailCommon::CollectionGeneralPageFactory);
290 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionMaintenancePageFactory);
291 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionQuotaPageFactory);
292 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionTemplatesPageFactory);
293 Akonadi::CollectionPropertiesDialog::registerPage(new MailCommon::CollectionExpiryPageFactory);
294 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionViewPageFactory);
295 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionMailingListPageFactory);
296 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionShortcutPageFactory);
298 pagesRegistered = true;
302 KMainWindow *mainWin = dynamic_cast<KMainWindow *>(window());
303 QStatusBar *sb = mainWin ? mainWin->statusBar() : Q_NULLPTR;
304 mVacationScriptIndicator = new KMail::VacationScriptIndicatorWidget(sb);
305 mVacationScriptIndicator->hide();
306 connect(mVacationScriptIndicator, &KMail::VacationScriptIndicatorWidget::clicked, this, &KMMainWidget::slotEditVacation);
307 if (KSieveUi::Util::checkOutOfOfficeOnStartup()) {
308 QTimer::singleShot(0, this, &KMMainWidget::slotCheckVacation);
311 connect(mFolderTreeWidget->folderTreeView()->model(), &QAbstractItemModel::modelReset,
312 this, &KMMainWidget::restoreCollectionFolderViewConfig);
313 restoreCollectionFolderViewConfig();
315 if (kmkernel->firstStart()) {
316 if (MailCommon::Util::foundMailer()) {
317 if (KMessageBox::questionYesNo(this, i18n("Another mailer was found on system. Do you want to import data from it?")) == KMessageBox::Yes) {
318 const QString path = QStandardPaths::findExecutable(QStringLiteral("importwizard"));
319 if (!QProcess::startDetached(path)) {
320 KMessageBox::error(this, i18n("Could not start the import wizard. "
321 "Please check your installation."),
322 i18n("Unable to start import wizard"));
324 } else {
325 mLaunchExternalComponent->slotAccountWizard();
327 } else {
328 mLaunchExternalComponent->slotAccountWizard();
331 // must be the last line of the constructor:
332 mStartupDone = true;
334 mCheckMailTimer.setInterval(3 * 1000);
335 mCheckMailTimer.setSingleShot(true);
336 connect(&mCheckMailTimer, &QTimer::timeout, this, &KMMainWidget::slotUpdateActionsAfterMailChecking);
340 void KMMainWidget::restoreCollectionFolderViewConfig()
342 ETMViewStateSaver *saver = new ETMViewStateSaver;
343 saver->setView(mFolderTreeWidget->folderTreeView());
344 const KConfigGroup cfg(KMKernel::self()->config(), "CollectionFolderView");
345 mFolderTreeWidget->restoreHeaderState(cfg.readEntry("HeaderState", QByteArray()));
346 saver->restoreState(cfg);
347 //Restore startup folder
349 Akonadi::Collection::Id id = -1;
350 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
351 id = mCurrentFolder->collection().id();
354 if (id == -1) {
355 if (KMailSettings::self()->startSpecificFolderAtStartup()) {
356 Akonadi::Collection::Id startupFolder = KMailSettings::self()->startupFolder();
357 if (startupFolder > 0) {
358 saver->restoreCurrentItem(QStringLiteral("c%1").arg(startupFolder));
361 } else {
362 saver->restoreCurrentItem(QStringLiteral("c%1").arg(id));
366 //-----------------------------------------------------------------------------
367 //The kernel may have already been deleted when this method is called,
368 //perform all cleanup that requires the kernel in destruct()
369 KMMainWidget::~KMMainWidget()
371 theMainWidgetList->removeAll(this);
372 qDeleteAll(mFilterCommands);
373 destruct();
376 //-----------------------------------------------------------------------------
377 //This method performs all cleanup that requires the kernel to exist.
378 void KMMainWidget::destruct()
380 if (mDestructed) {
381 return;
383 if (mSearchWin) {
384 mSearchWin->close();
386 writeConfig(false); /* don't force kmkernel sync when close BUG: 289287 */
387 writeFolderConfig();
388 deleteWidgets();
389 mCurrentFolder.clear();
390 delete mMoveOrCopyToDialog;
391 delete mSelectFromAllFoldersDialog;
393 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), this, Q_NULLPTR);
394 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)), this, Q_NULLPTR);
395 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), this, Q_NULLPTR);
396 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)), this, Q_NULLPTR);
397 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), this, Q_NULLPTR);
399 mDestructed = true;
402 void KMMainWidget::slotStartCheckMail()
404 if (mCheckMailTimer.isActive()) {
405 mCheckMailTimer.stop();
409 void KMMainWidget::slotEndCheckMail()
411 if (!mCheckMailTimer.isActive()) {
412 mCheckMailTimer.start();
416 void KMMainWidget::slotUpdateActionsAfterMailChecking()
418 const bool sendOnAll =
419 KMailSettings::self()->sendOnCheck() == KMailSettings::EnumSendOnCheck::SendOnAllChecks;
420 const bool sendOnManual =
421 KMailSettings::self()->sendOnCheck() == KMailSettings::EnumSendOnCheck::SendOnManualChecks;
422 if (!kmkernel->isOffline() && (sendOnAll || sendOnManual)) {
423 slotSendQueued();
425 // update folder menus in case some mail got filtered to trash/current folder
426 // and we can enable "empty trash/move all to trash" action etc.
427 updateFolderMenu();
430 void KMMainWidget::slotCollectionFetched(int collectionId)
432 // Called when a collection is fetched for the first time by the ETM.
433 // This is the right time to update the caption (which still says "Loading...")
434 // and to update the actions that depend on the number of mails in the folder.
435 if (mCurrentFolder && collectionId == mCurrentFolder->collection().id()) {
436 mCurrentFolder->setCollection(MailCommon::Util::updatedCollection(mCurrentFolder->collection()));
437 updateMessageActions();
438 updateFolderMenu();
440 // We call this for any collection, it could be one of our parents...
441 if (mCurrentFolder) {
442 Q_EMIT captionChangeRequest(MailCommon::Util::fullCollectionPath(mCurrentFolder->collection()));
446 void KMMainWidget::slotFolderChanged(const Akonadi::Collection &collection)
448 folderSelected(collection);
449 if (collection.cachePolicy().syncOnDemand()) {
450 AgentManager::self()->synchronizeCollection(collection, false);
452 mMsgActions->setCurrentMessage(Akonadi::Item());
453 Q_EMIT captionChangeRequest(MailCommon::Util::fullCollectionPath(collection));
456 void KMMainWidget::folderSelected(const Akonadi::Collection &col)
458 // This is connected to the MainFolderView signal triggering when a folder is selected
460 if (mGoToFirstUnreadMessageInSelectedFolder) {
461 // the default action has been overridden from outside
462 mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered;
463 } else {
464 // use the default action
465 switch (KMailSettings::self()->actionEnterFolder()) {
466 case KMailSettings::EnumActionEnterFolder::SelectFirstUnread:
467 mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered;
468 break;
469 case KMailSettings::EnumActionEnterFolder::SelectLastSelected:
470 mPreSelectionMode = MessageList::Core::PreSelectLastSelected;
471 break;
472 case KMailSettings::EnumActionEnterFolder::SelectNewest:
473 mPreSelectionMode = MessageList::Core::PreSelectNewestCentered;
474 break;
475 case KMailSettings::EnumActionEnterFolder::SelectOldest:
476 mPreSelectionMode = MessageList::Core::PreSelectOldestCentered;
477 break;
478 default:
479 mPreSelectionMode = MessageList::Core::PreSelectNone;
480 break;
484 mGoToFirstUnreadMessageInSelectedFolder = false;
485 #ifndef QT_NO_CURSOR
486 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
487 #endif
489 if (mMsgView) {
490 mMsgView->clear(true);
492 const bool newFolder = mCurrentFolder && (mCurrentFolder->collection() != col);
494 // Delete any pending timer, if needed it will be recreated below
495 delete mShowBusySplashTimer;
496 mShowBusySplashTimer = Q_NULLPTR;
497 if (newFolder) {
498 // We're changing folder: write configuration for the old one
499 writeFolderConfig();
502 mCurrentFolder = FolderCollection::forCollection(col);
504 readFolderConfig();
505 if (mMsgView) {
506 mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
507 mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
510 if (!mCurrentFolder->isValid() && (mMessagePane->count() < 2)) {
511 slotIntro();
514 updateMessageActions();
515 updateFolderMenu();
517 // The message pane uses the selection model of the folder view to load the correct aggregation model and theme
518 // settings. At this point the selection model hasn't been updated yet to the user's new choice, so it would load
519 // the old folder settings instead.
520 QTimer::singleShot(0, this, &KMMainWidget::slotShowSelectedFolderInPane);
523 void KMMainWidget::slotShowSelectedFolderInPane()
525 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
526 mMessagePane->setCurrentFolder(mCurrentFolder->collection(), false, mPreSelectionMode);
530 void KMMainWidget::clearViewer()
532 if (mMsgView) {
533 mMsgView->clear(true);
534 mMsgView->displayAboutPage();
538 //-----------------------------------------------------------------------------
539 void KMMainWidget::readPreConfig()
541 mLongFolderList = KMailSettings::self()->folderList() == KMailSettings::EnumFolderList::longlist;
542 mReaderWindowActive = KMailSettings::self()->readerWindowMode() != KMailSettings::EnumReaderWindowMode::hide;
543 mReaderWindowBelow = KMailSettings::self()->readerWindowMode() == KMailSettings::EnumReaderWindowMode::below;
545 mHtmlGlobalSetting = MessageViewer::MessageViewerSettings::self()->htmlMail();
546 mHtmlLoadExtGlobalSetting = MessageViewer::MessageViewerSettings::self()->htmlLoadExternal();
548 mEnableFavoriteFolderView = (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() != MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode);
549 mEnableFolderQuickSearch = KMailSettings::self()->enableFolderQuickSearch();
550 readFolderConfig();
551 updateHtmlMenuEntry();
552 if (mMsgView) {
553 mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
554 mMsgView->update(true);
558 //-----------------------------------------------------------------------------
559 void KMMainWidget::readFolderConfig()
561 if (!mCurrentFolder || !mCurrentFolder->isValid()) {
562 return;
564 KSharedConfig::Ptr config = KMKernel::self()->config();
565 KConfigGroup group(config, MailCommon::FolderCollection::configGroupName(mCurrentFolder->collection()));
566 if (group.hasKey("htmlMailOverride")) {
567 const bool useHtml = group.readEntry("htmlMailOverride", false);
568 mFolderDisplayFormatPreference = useHtml ? MessageViewer::Viewer::Html : MessageViewer::Viewer::Text;
569 group.deleteEntry("htmlMailOverride");
570 group.sync();
571 } else {
572 mFolderDisplayFormatPreference = static_cast<MessageViewer::Viewer::DisplayFormatMessage>(group.readEntry("displayFormatOverride", static_cast<int>(MessageViewer::Viewer::UseGlobalSetting)));
574 mFolderHtmlLoadExtPreference =
575 group.readEntry("htmlLoadExternalOverride", false);
578 //-----------------------------------------------------------------------------
579 void KMMainWidget::writeFolderConfig()
581 if (mCurrentFolder && mCurrentFolder->isValid()) {
582 KSharedConfig::Ptr config = KMKernel::self()->config();
583 KConfigGroup group(config, MailCommon::FolderCollection::configGroupName(mCurrentFolder->collection()));
584 group.writeEntry("htmlLoadExternalOverride", mFolderHtmlLoadExtPreference);
585 if (mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting) {
586 group.deleteEntry("displayFormatOverride");
587 } else {
588 group.writeEntry("displayFormatOverride", static_cast<int>(mFolderDisplayFormatPreference));
593 //-----------------------------------------------------------------------------
594 void KMMainWidget::layoutSplitters()
596 // This function can only be called when the old splitters are already deleted
597 Q_ASSERT(!mSplitter1);
598 Q_ASSERT(!mSplitter2);
600 // For some reason, this is necessary here so that the copy action still
601 // works after changing the folder layout.
602 if (mMsgView)
603 disconnect(mMsgView->copyAction(), &QAction::triggered,
604 mMsgView, &KMReaderWin::slotCopySelectedText);
606 // If long folder list is enabled, the splitters are:
607 // Splitter 1: FolderView vs (HeaderAndSearch vs MessageViewer)
608 // Splitter 2: HeaderAndSearch vs MessageViewer
610 // If long folder list is disabled, the splitters are:
611 // Splitter 1: (FolderView vs HeaderAndSearch) vs MessageViewer
612 // Splitter 2: FolderView vs HeaderAndSearch
614 // The folder view is both the folder tree and the favorite folder view, if
615 // enabled
617 const bool readerWindowAtSide = !mReaderWindowBelow && mReaderWindowActive;
618 const bool readerWindowBelow = mReaderWindowBelow && mReaderWindowActive;
620 mSplitter1 = new QSplitter(this);
621 mSplitter2 = new QSplitter(mSplitter1);
623 QWidget *folderTreeWidget = mSearchAndTree;
624 if (mFavoriteCollectionsView) {
625 mFolderViewSplitter = new QSplitter(Qt::Vertical);
626 //mFolderViewSplitter->setChildrenCollapsible( false );
627 mFolderViewSplitter->addWidget(mFavoriteCollectionsView);
628 mFavoriteCollectionsView->setParent(mFolderViewSplitter);
629 mFolderViewSplitter->addWidget(mSearchAndTree);
630 folderTreeWidget = mFolderViewSplitter;
633 if (mLongFolderList) {
635 // add folder tree
636 mSplitter1->setOrientation(Qt::Horizontal);
637 mSplitter1->addWidget(folderTreeWidget);
639 // and the rest to the right
640 mSplitter1->addWidget(mSplitter2);
642 // add the message list to the right or below
643 if (readerWindowAtSide) {
644 mSplitter2->setOrientation(Qt::Horizontal);
645 } else {
646 mSplitter2->setOrientation(Qt::Vertical);
648 mSplitter2->addWidget(mMessagePane);
650 // add the preview window, if there is one
651 if (mMsgView) {
652 mSplitter2->addWidget(mMsgView);
655 } else { // short folder list
656 if (mReaderWindowBelow) {
657 mSplitter1->setOrientation(Qt::Vertical);
658 mSplitter2->setOrientation(Qt::Horizontal);
659 } else { // at side or none
660 mSplitter1->setOrientation(Qt::Horizontal);
661 mSplitter2->setOrientation(Qt::Vertical);
664 mSplitter1->addWidget(mSplitter2);
666 // add folder tree
667 mSplitter2->addWidget(folderTreeWidget);
668 // add message list to splitter 2
669 mSplitter2->addWidget(mMessagePane);
671 // add the preview window, if there is one
672 if (mMsgView) {
673 mSplitter1->addWidget(mMsgView);
678 // Set splitter properties
680 mSplitter1->setObjectName(QStringLiteral("splitter1"));
681 //mSplitter1->setChildrenCollapsible( false );
682 mSplitter2->setObjectName(QStringLiteral("splitter2"));
683 //mSplitter2->setChildrenCollapsible( false );
686 // Set the stretch factors
688 mSplitter1->setStretchFactor(0, 0);
689 mSplitter2->setStretchFactor(0, 0);
690 mSplitter1->setStretchFactor(1, 1);
691 mSplitter2->setStretchFactor(1, 1);
693 if (mFavoriteCollectionsView) {
694 mFolderViewSplitter->setStretchFactor(0, 0);
695 mFolderViewSplitter->setStretchFactor(1, 1);
698 // Because the reader windows's width increases a tiny bit after each
699 // restart in short folder list mode with message window at side, disable
700 // the stretching as a workaround here
701 if (readerWindowAtSide && !mLongFolderList) {
702 mSplitter1->setStretchFactor(0, 1);
703 mSplitter1->setStretchFactor(1, 0);
707 // Set the sizes of the splitters to the values stored in the config
709 QList<int> splitter1Sizes;
710 QList<int> splitter2Sizes;
712 const int folderViewWidth = KMailSettings::self()->folderViewWidth();
713 int ftHeight = KMailSettings::self()->folderTreeHeight();
714 int headerHeight = KMailSettings::self()->searchAndHeaderHeight();
715 const int messageViewerWidth = KMailSettings::self()->readerWindowWidth();
716 int headerWidth = KMailSettings::self()->searchAndHeaderWidth();
717 int messageViewerHeight = KMailSettings::self()->readerWindowHeight();
719 int ffvHeight = mFolderViewSplitter ? MailCommon::MailCommonSettings::self()->favoriteCollectionViewHeight() : 0;
721 // If the message viewer was hidden before, make sure it is not zero height
722 if (messageViewerHeight < 10 && readerWindowBelow) {
723 headerHeight /= 2;
724 messageViewerHeight = headerHeight;
727 if (mLongFolderList) {
728 if (!readerWindowAtSide) {
729 splitter1Sizes << folderViewWidth << headerWidth;
730 splitter2Sizes << headerHeight << messageViewerHeight;
731 } else {
732 splitter1Sizes << folderViewWidth << (headerWidth + messageViewerWidth);
733 splitter2Sizes << headerWidth << messageViewerWidth;
735 } else {
736 if (!readerWindowAtSide) {
737 splitter1Sizes << headerHeight << messageViewerHeight;
738 splitter2Sizes << folderViewWidth << headerWidth;
739 } else {
740 splitter1Sizes << headerWidth << messageViewerWidth;
741 splitter2Sizes << ftHeight + ffvHeight << messageViewerHeight;
745 mSplitter1->setSizes(splitter1Sizes);
746 mSplitter2->setSizes(splitter2Sizes);
748 if (mFolderViewSplitter) {
749 QList<int> splitterSizes;
750 splitterSizes << ffvHeight << ftHeight;
751 mFolderViewSplitter->setSizes(splitterSizes);
755 // Now add the splitters to the main layout
757 mTopLayout->addWidget(mSplitter1);
759 // Make sure the focus is on the view, and not on the quick search line edit, because otherwise
760 // shortcuts like + or j go to the wrong place.
761 // This would normally be done in the message list itself, but apparently something resets the focus
762 // again, probably all the reparenting we do here.
763 mMessagePane->focusView();
765 // By default hide th unread and size columns on first run.
766 if (kmkernel->firstStart()) {
767 mFolderTreeWidget->folderTreeView()->hideColumn(1);
768 mFolderTreeWidget->folderTreeView()->hideColumn(3);
769 mFolderTreeWidget->folderTreeView()->header()->resizeSection(0, folderViewWidth * 0.8);
772 // Make the copy action work, see disconnect comment above
773 if (mMsgView)
774 connect(mMsgView->copyAction(), &QAction::triggered,
775 mMsgView, &KMReaderWin::slotCopySelectedText);
778 //-----------------------------------------------------------------------------
779 void KMMainWidget::refreshFavoriteFoldersViewProperties()
781 if (mFavoriteCollectionsView) {
782 if (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode) {
783 mFavoriteCollectionsView->changeViewMode(QListView::IconMode);
784 } else if (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode) {
785 mFavoriteCollectionsView->changeViewMode(QListView::ListMode);
786 } else {
787 Q_ASSERT(false); // we should never get here in hidden mode
789 mFavoriteCollectionsView->setDropActionMenuEnabled(kmkernel->showPopupAfterDnD());
790 mFavoriteCollectionsView->setWordWrap(true);
791 mFavoriteCollectionsView->updateMode();
795 //-----------------------------------------------------------------------------
796 void KMMainWidget::readConfig()
798 const bool oldLongFolderList = mLongFolderList;
799 const bool oldReaderWindowActive = mReaderWindowActive;
800 const bool oldReaderWindowBelow = mReaderWindowBelow;
801 const bool oldFavoriteFolderView = mEnableFavoriteFolderView;
802 const bool oldFolderQuickSearch = mEnableFolderQuickSearch;
804 // on startup, the layout is always new and we need to relayout the widgets
805 bool layoutChanged = !mStartupDone;
807 if (mStartupDone) {
808 readPreConfig();
810 layoutChanged = (oldLongFolderList != mLongFolderList) ||
811 (oldReaderWindowActive != mReaderWindowActive) ||
812 (oldReaderWindowBelow != mReaderWindowBelow) ||
813 (oldFavoriteFolderView != mEnableFavoriteFolderView);
815 if (layoutChanged) {
816 deleteWidgets();
817 createWidgets();
818 restoreCollectionFolderViewConfig();
819 Q_EMIT recreateGui();
820 } else if (oldFolderQuickSearch != mEnableFolderQuickSearch) {
821 if (mEnableFolderQuickSearch) {
822 mFolderTreeWidget->filterFolderLineEdit()->show();
823 } else {
824 mFolderTreeWidget->filterFolderLineEdit()->hide();
830 // Read the config of the folder views and the header
831 if (mMsgView) {
832 mMsgView->readConfig();
834 mMessagePane->reloadGlobalConfiguration();
835 mFolderTreeWidget->readConfig();
836 if (mFavoriteCollectionsView) {
837 mFavoriteCollectionsView->readConfig();
839 refreshFavoriteFoldersViewProperties();
843 // area for config group "General"
844 if (!mStartupDone) {
845 // check mail on startup
846 // do it after building the kmmainwin, so that the progressdialog is available
847 QTimer::singleShot(0, this, &KMMainWidget::slotCheckMailOnStartup);
851 if (layoutChanged) {
852 layoutSplitters();
855 updateMessageMenu();
856 updateFileMenu();
857 kmkernel->toggleSystemTray();
859 connect(Akonadi::AgentManager::self(), &AgentManager::instanceAdded,
860 this, &KMMainWidget::updateFileMenu);
861 connect(Akonadi::AgentManager::self(), &AgentManager::instanceRemoved,
862 this, &KMMainWidget::updateFileMenu);
865 //-----------------------------------------------------------------------------
866 void KMMainWidget::writeConfig(bool force)
868 // Don't save the sizes of all the widgets when we were never shown.
869 // This can happen in Kontact, where the KMail plugin is automatically
870 // loaded, but not necessarily shown.
871 // This prevents invalid sizes from being saved
872 if (mWasEverShown) {
873 // The height of the header widget can be 0, this happens when the user
874 // did not switch to the header widget onced and the "Welcome to KMail"
875 // HTML widget was shown the whole time
876 int headersHeight = mMessagePane->height();
877 if (headersHeight == 0) {
878 headersHeight = height() / 2;
881 KMailSettings::self()->setSearchAndHeaderHeight(headersHeight);
882 KMailSettings::self()->setSearchAndHeaderWidth(mMessagePane->width());
883 if (mFavoriteCollectionsView) {
884 MailCommon::MailCommonSettings::self()->setFavoriteCollectionViewHeight(mFavoriteCollectionsView->height());
885 KMailSettings::self()->setFolderTreeHeight(mFolderTreeWidget->height());
886 if (!mLongFolderList) {
887 KMailSettings::self()->setFolderViewHeight(mFolderViewSplitter->height());
889 } else if (!mLongFolderList && mFolderTreeWidget) {
890 KMailSettings::self()->setFolderTreeHeight(mFolderTreeWidget->height());
892 if (mFolderTreeWidget) {
893 KMailSettings::self()->setFolderViewWidth(mFolderTreeWidget->width());
894 KSharedConfig::Ptr config = KMKernel::self()->config();
895 KConfigGroup group(config, "CollectionFolderView");
897 ETMViewStateSaver saver;
898 saver.setView(mFolderTreeWidget->folderTreeView());
899 saver.saveState(group);
901 group.writeEntry("HeaderState", mFolderTreeWidget->folderTreeView()->header()->saveState());
902 //Work around from startup folder
903 group.deleteEntry("Selection");
904 #if 0
905 if (!KMailSettings::self()->startSpecificFolderAtStartup()) {
906 group.deleteEntry("Current");
908 #endif
909 group.sync();
912 if (mMsgView) {
913 if (!mReaderWindowBelow) {
914 KMailSettings::self()->setReaderWindowWidth(mMsgView->width());
916 mMsgView->viewer()->writeConfig(force);
917 KMailSettings::self()->setReaderWindowHeight(mMsgView->height());
922 void KMMainWidget::writeReaderConfig()
924 if (mWasEverShown) {
925 if (mMsgView) {
926 mMsgView->viewer()->writeConfig();
931 KMReaderWin *KMMainWidget::messageView() const
933 return mMsgView;
936 CollectionPane *KMMainWidget::messageListPane() const
938 return mMessagePane;
941 //-----------------------------------------------------------------------------
942 void KMMainWidget::deleteWidgets()
944 // Simply delete the top splitter, which always is mSplitter1, regardless
945 // of the layout. This deletes all children.
946 // akonadi action manager is created in createWidgets(), parented to this
947 // so not autocleaned up.
948 delete mAkonadiStandardActionManager;
949 mAkonadiStandardActionManager = Q_NULLPTR;
950 delete mSplitter1;
951 mMsgView = Q_NULLPTR;
952 mSearchAndTree = Q_NULLPTR;
953 mFolderViewSplitter = Q_NULLPTR;
954 mFavoriteCollectionsView = Q_NULLPTR;
955 mSplitter1 = Q_NULLPTR;
956 mSplitter2 = Q_NULLPTR;
957 mFavoritesModel = Q_NULLPTR;
960 //-----------------------------------------------------------------------------
961 void KMMainWidget::createWidgets()
963 // Note that all widgets we create in this function have the parent 'this'.
964 // They will be properly reparented in layoutSplitters()
967 // Create header view and search bar
969 FolderTreeWidget::TreeViewOptions opt = FolderTreeWidget::ShowUnreadCount;
970 opt |= FolderTreeWidget::UseLineEditForFiltering;
971 opt |= FolderTreeWidget::ShowCollectionStatisticAnimation;
972 opt |= FolderTreeWidget::DontKeyFilter;
973 mFolderTreeWidget = new FolderTreeWidget(this, mGUIClient, opt);
975 connect(mFolderTreeWidget->folderTreeView(), SIGNAL(currentChanged(Akonadi::Collection)), this, SLOT(slotFolderChanged(Akonadi::Collection)));
977 connect(mFolderTreeWidget->folderTreeView()->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KMMainWidget::updateFolderMenu);
979 connect(mFolderTreeWidget->folderTreeView(), &FolderTreeView::prefereCreateNewTab, this, &KMMainWidget::slotCreateNewTab);
981 mFolderTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
982 mMessagePane = new CollectionPane(!KMailSettings::self()->startSpecificFolderAtStartup(), KMKernel::self()->entityTreeModel(),
983 mFolderTreeWidget->folderTreeView()->selectionModel(),
984 this);
985 connect(KMKernel::self()->entityTreeModel(), &Akonadi::EntityTreeModel::collectionFetched, this, &KMMainWidget::slotCollectionFetched);
987 mMessagePane->setXmlGuiClient(mGUIClient);
988 connect(mMessagePane, &MessageList::Pane::messageSelected,
989 this, &KMMainWidget::slotMessageSelected);
990 connect(mMessagePane, &MessageList::Pane::selectionChanged,
991 this, &KMMainWidget::startUpdateMessageActionsTimer);
992 connect(mMessagePane, &CollectionPane::currentTabChanged, this, &KMMainWidget::refreshMessageListSelection);
993 connect(mMessagePane, &MessageList::Pane::messageActivated,
994 this, &KMMainWidget::slotMessageActivated);
995 connect(mMessagePane, &MessageList::Pane::messageStatusChangeRequest,
996 this, &KMMainWidget::slotMessageStatusChangeRequest);
998 connect(mMessagePane, &MessageList::Pane::statusMessage,
999 BroadcastStatus::instance(), &KPIM::BroadcastStatus::setStatusMsg);
1002 // Create the reader window
1004 if (mReaderWindowActive) {
1005 mMsgView = new KMReaderWin(this, this, actionCollection(), Q_NULLPTR);
1006 if (mMsgActions) {
1007 mMsgActions->setMessageView(mMsgView);
1009 connect(mMsgView->viewer(), &MessageViewer::Viewer::replaceMsgByUnencryptedVersion,
1010 this, &KMMainWidget::slotReplaceMsgByUnencryptedVersion);
1011 connect(mMsgView->viewer(), &MessageViewer::Viewer::popupMenu,
1012 this, &KMMainWidget::slotMessagePopup);
1013 connect(mMsgView->viewer(), &MessageViewer::Viewer::moveMessageToTrash,
1014 this, &KMMainWidget::slotMoveMessageToTrash);
1015 if (mShowIntroductionAction) {
1016 mShowIntroductionAction->setEnabled(true);
1018 } else {
1019 if (mMsgActions) {
1020 mMsgActions->setMessageView(Q_NULLPTR);
1022 if (mShowIntroductionAction) {
1023 mShowIntroductionAction->setEnabled(false);
1028 // Create the folder tree
1029 // the "folder tree" consists of a quicksearch input field and the tree itself
1032 mSearchAndTree = new QWidget(this);
1033 QVBoxLayout *vboxlayout = new QVBoxLayout;
1034 vboxlayout->setMargin(0);
1035 mSearchAndTree->setLayout(vboxlayout);
1037 vboxlayout->addWidget(mFolderTreeWidget);
1039 if (!KMailSettings::self()->enableFolderQuickSearch()) {
1040 mFolderTreeWidget->filterFolderLineEdit()->hide();
1043 // Create the favorite folder view
1045 mAkonadiStandardActionManager = new Akonadi::StandardMailActionManager(mGUIClient->actionCollection(), this);
1046 connect(mAkonadiStandardActionManager, &Akonadi::StandardMailActionManager::actionStateUpdated, this, &KMMainWidget::slotAkonadiStandardActionUpdated);
1048 mAkonadiStandardActionManager->setCollectionSelectionModel(mFolderTreeWidget->folderTreeView()->selectionModel());
1049 mAkonadiStandardActionManager->setItemSelectionModel(mMessagePane->currentItemSelectionModel());
1051 if (mEnableFavoriteFolderView) {
1053 mFavoriteCollectionsView = new FavoriteCollectionWidget(mGUIClient, this);
1054 refreshFavoriteFoldersViewProperties();
1055 connect(mFavoriteCollectionsView, SIGNAL(currentChanged(Akonadi::Collection)), this, SLOT(slotFolderChanged(Akonadi::Collection)));
1057 mFavoritesModel = new Akonadi::FavoriteCollectionsModel(
1058 mFolderTreeWidget->folderTreeView()->model(),
1059 KMKernel::self()->config()->group("FavoriteCollections"), this);
1061 mFavoriteCollectionsView->setModel(mFavoritesModel);
1063 mAkonadiStandardActionManager->setFavoriteCollectionsModel(mFavoritesModel);
1064 mAkonadiStandardActionManager->setFavoriteSelectionModel(mFavoriteCollectionsView->selectionModel());
1067 //Don't use mMailActionManager->createAllActions() to save memory by not
1068 //creating actions that doesn't make sense.
1069 QList<StandardActionManager::Type> standardActions;
1070 standardActions << StandardActionManager::CreateCollection
1071 << StandardActionManager::CopyCollections
1072 << StandardActionManager::DeleteCollections
1073 << StandardActionManager::SynchronizeCollections
1074 << StandardActionManager::CollectionProperties
1075 << StandardActionManager::CopyItems
1076 << StandardActionManager::Paste
1077 << StandardActionManager::DeleteItems
1078 << StandardActionManager::ManageLocalSubscriptions
1079 << StandardActionManager::CopyCollectionToMenu
1080 << StandardActionManager::CopyItemToMenu
1081 << StandardActionManager::MoveItemToMenu
1082 << StandardActionManager::MoveCollectionToMenu
1083 << StandardActionManager::CutItems
1084 << StandardActionManager::CutCollections
1085 << StandardActionManager::CreateResource
1086 << StandardActionManager::DeleteResources
1087 << StandardActionManager::ResourceProperties
1088 << StandardActionManager::SynchronizeResources
1089 << StandardActionManager::ToggleWorkOffline
1090 << StandardActionManager::SynchronizeCollectionsRecursive;
1092 Q_FOREACH (StandardActionManager::Type standardAction, standardActions) {
1093 mAkonadiStandardActionManager->createAction(standardAction);
1096 if (mEnableFavoriteFolderView) {
1097 QList<StandardActionManager::Type> favoriteActions;
1098 favoriteActions << StandardActionManager::AddToFavoriteCollections
1099 << StandardActionManager::RemoveFromFavoriteCollections
1100 << StandardActionManager::RenameFavoriteCollection
1101 << StandardActionManager::SynchronizeFavoriteCollections;
1102 Q_FOREACH (StandardActionManager::Type favoriteAction, favoriteActions) {
1103 mAkonadiStandardActionManager->createAction(favoriteAction);
1107 QList<StandardMailActionManager::Type> mailActions;
1108 mailActions << StandardMailActionManager::MarkAllMailAsRead
1109 << StandardMailActionManager::MoveToTrash
1110 << StandardMailActionManager::MoveAllToTrash
1111 << StandardMailActionManager::RemoveDuplicates
1112 << StandardMailActionManager::EmptyAllTrash
1113 << StandardMailActionManager::MarkMailAsRead
1114 << StandardMailActionManager::MarkMailAsUnread
1115 << StandardMailActionManager::MarkMailAsImportant
1116 << StandardMailActionManager::MarkMailAsActionItem;
1118 Q_FOREACH (StandardMailActionManager::Type mailAction, mailActions) {
1119 mAkonadiStandardActionManager->createAction(mailAction);
1122 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardActionManager::CollectionProperties);
1123 connect(mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CollectionProperties), &QAction::triggered, mManageShowCollectionProperties, &ManageShowCollectionProperties::slotCollectionProperties);
1126 // Create all kinds of actions
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), &QAction::triggered, this, &KMMainWidget::slotRemoveDuplicates);
1133 mCollectionProperties = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CollectionProperties);
1135 connect(kmkernel->folderCollectionMonitor(), &Monitor::collectionRemoved,
1136 this, &KMMainWidget::slotCollectionRemoved);
1137 connect(kmkernel->folderCollectionMonitor(), &Monitor::itemAdded,
1138 this, &KMMainWidget::slotItemAdded);
1139 connect(kmkernel->folderCollectionMonitor(), &Monitor::itemRemoved,
1140 this, &KMMainWidget::slotItemRemoved);
1141 connect(kmkernel->folderCollectionMonitor(), &Monitor::itemMoved,
1142 this, &KMMainWidget::slotItemMoved);
1143 connect(kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)), SLOT(slotCollectionChanged(Akonadi::Collection,QSet<QByteArray>)));
1145 connect(kmkernel->folderCollectionMonitor(), &Monitor::collectionStatisticsChanged, this, &KMMainWidget::slotCollectionStatisticsChanged);
1149 void KMMainWidget::updateMoveAction(const Akonadi::CollectionStatistics &statistic)
1151 const bool hasUnreadMails = (statistic.unreadCount() > 0);
1152 const bool hasMails = (statistic.count() > 0);
1153 updateMoveAction(hasUnreadMails, hasMails);
1156 void KMMainWidget::updateMoveAction(bool hasUnreadMails, bool hasMails)
1158 const bool enable_goto_unread = hasUnreadMails
1159 || (KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders)
1160 || (KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders);
1161 actionCollection()->action(QStringLiteral("go_next_message"))->setEnabled(hasMails);
1162 actionCollection()->action(QStringLiteral("go_next_unread_message"))->setEnabled(enable_goto_unread);
1163 actionCollection()->action(QStringLiteral("go_prev_message"))->setEnabled(hasMails);
1164 actionCollection()->action(QStringLiteral("go_prev_unread_message"))->setEnabled(enable_goto_unread);
1165 if (mAkonadiStandardActionManager && mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MarkAllMailAsRead)) {
1166 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MarkAllMailAsRead)->setEnabled(hasUnreadMails);
1170 void KMMainWidget::updateAllToTrashAction(int statistics)
1172 bool multiFolder = false;
1173 if (mFolderTreeWidget) {
1174 multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
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);
1185 void KMMainWidget::slotCollectionStatisticsChanged(const Akonadi::Collection::Id id, const Akonadi::CollectionStatistics &statistic)
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()));
1198 void KMMainWidget::slotCreateNewTab(bool preferNewTab)
1200 mMessagePane->setPreferEmptyTab(preferNewTab);
1203 void KMMainWidget::slotCollectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &set)
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);
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);
1223 void KMMainWidget::slotItemAdded(const Akonadi::Item &msg, const Akonadi::Collection &col)
1225 Q_UNUSED(msg);
1226 if (col.isValid()) {
1227 if (col == CommonKernel->outboxCollectionFolder()) {
1228 startUpdateMessageActionsTimer();
1233 void KMMainWidget::slotItemRemoved(const Akonadi::Item &item)
1235 if (item.isValid() && item.parentCollection().isValid() && (item.parentCollection() == CommonKernel->outboxCollectionFolder())) {
1236 startUpdateMessageActionsTimer();
1240 void KMMainWidget::slotItemMoved(const Akonadi::Item &item, const Akonadi::Collection &from, const Akonadi::Collection &to)
1242 if (item.isValid() && ((from.id() == CommonKernel->outboxCollectionFolder().id())
1243 || to.id() == CommonKernel->outboxCollectionFolder().id())) {
1244 startUpdateMessageActionsTimer();
1248 //-------------------------------------------------------------------------
1249 void KMMainWidget::slotFocusQuickSearch()
1251 const QString text = mMsgView ? mMsgView->copyText() : QString();
1252 mMessagePane->focusQuickSearch(text);
1255 //-------------------------------------------------------------------------
1256 bool KMMainWidget::slotSearch()
1258 if (!mSearchWin) {
1259 mSearchWin = new SearchWindow(this, mCurrentFolder ? mCurrentFolder->collection() : Akonadi::Collection());
1260 mSearchWin->setModal(false);
1261 mSearchWin->setObjectName(QStringLiteral("Search"));
1262 } else {
1263 mSearchWin->activateFolder(mCurrentFolder ? mCurrentFolder->collection() : Akonadi::Collection());
1266 mSearchWin->show();
1267 KWindowSystem::activateWindow(mSearchWin->winId());
1268 return true;
1271 //-----------------------------------------------------------------------------
1272 void KMMainWidget::slotHelp()
1274 KHelpClient::invokeHelp();
1277 //-----------------------------------------------------------------------------
1278 void KMMainWidget::slotFilter()
1280 FilterIf->openFilterDialog(true);
1283 void KMMainWidget::slotManageSieveScripts()
1285 if (!kmkernel->askToGoOnline()) {
1286 return;
1288 if (mManageSieveDialog) {
1289 return;
1292 mManageSieveDialog = new KSieveUi::ManageSieveScriptsDialog;
1293 connect(mManageSieveDialog.data(), &KSieveUi::ManageSieveScriptsDialog::finished, this, &KMMainWidget::slotCheckVacation);
1294 mManageSieveDialog->show();
1297 //-----------------------------------------------------------------------------
1298 void KMMainWidget::slotCheckMail()
1300 kmkernel->checkMail();
1303 //-----------------------------------------------------------------------------
1304 void KMMainWidget::slotCheckMailOnStartup()
1306 kmkernel->checkMailOnStartup();
1309 void KMMainWidget::slotCompose()
1311 KMail::Composer *win;
1312 KMime::Message::Ptr msg(new KMime::Message());
1314 bool forceCursorPosition = false;
1315 if (mCurrentFolder) {
1316 MessageHelper::initHeader(msg, KMKernel::self()->identityManager(), mCurrentFolder->identity());
1317 //Laurent: bug 289905
1319 if ( mCurrentFolder->collection().isValid() && mCurrentFolder->putRepliesInSameFolder() ) {
1320 KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Fcc", msg.get(), QString::number( mCurrentFolder->collection().id() ), "utf-8" );
1321 msg->setHeader( header );
1324 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
1325 parser.setIdentityManager(KMKernel::self()->identityManager());
1326 parser.process(msg, mCurrentFolder->collection());
1327 win = KMail::makeComposer(msg, false, false, KMail::Composer::New, mCurrentFolder->identity());
1328 win->setCollectionForNewMessage(mCurrentFolder->collection());
1329 forceCursorPosition = parser.cursorPositionWasSet();
1330 } else {
1331 MessageHelper::initHeader(msg, KMKernel::self()->identityManager());
1332 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
1333 parser.setIdentityManager(KMKernel::self()->identityManager());
1334 parser.process(KMime::Message::Ptr(), Akonadi::Collection());
1335 win = KMail::makeComposer(msg, false, false, KMail::Composer::New);
1336 forceCursorPosition = parser.cursorPositionWasSet();
1338 if (forceCursorPosition) {
1339 win->setFocusToEditor();
1341 win->show();
1345 //-----------------------------------------------------------------------------
1346 // TODO: do we want the list sorted alphabetically?
1347 void KMMainWidget::slotShowNewFromTemplate()
1349 if (mCurrentFolder) {
1350 const KIdentityManagement::Identity &ident =
1351 kmkernel->identityManager()->identityForUoidOrDefault(mCurrentFolder->identity());
1352 mTemplateFolder = CommonKernel->collectionFromId(ident.templates().toLongLong());
1355 if (!mTemplateFolder.isValid()) {
1356 mTemplateFolder = CommonKernel->templatesCollectionFolder();
1358 if (!mTemplateFolder.isValid()) {
1359 return;
1362 mTemplateMenu->menu()->clear();
1364 Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mTemplateFolder);
1365 job->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent);
1366 job->fetchScope().fetchFullPayload();
1367 connect(job, &Akonadi::ItemFetchJob::result, this, &KMMainWidget::slotDelayedShowNewFromTemplate);
1370 void KMMainWidget::slotDelayedShowNewFromTemplate(KJob *job)
1372 Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob *>(job);
1374 const Akonadi::Item::List items = fetchJob->items();
1375 const int numberOfItems = items.count();
1376 for (int idx = 0; idx < numberOfItems; ++idx) {
1377 KMime::Message::Ptr msg = MessageCore::Util::message(items.at(idx));
1378 if (msg) {
1379 QString subj = msg->subject()->asUnicodeString();
1380 if (subj.isEmpty()) {
1381 subj = i18n("No Subject");
1384 QAction *templateAction = mTemplateMenu->menu()->addAction(KStringHandler::rsqueeze(subj.replace(QLatin1Char('&'), QStringLiteral("&&"))));
1385 QVariant var;
1386 var.setValue(items.at(idx));
1387 templateAction->setData(var);
1391 // If there are no templates available, add a menu entry which informs
1392 // the user about this.
1393 if (mTemplateMenu->menu()->actions().isEmpty()) {
1394 QAction *noAction = mTemplateMenu->menu()->addAction(
1395 i18n("(no templates)"));
1396 noAction->setEnabled(false);
1400 //-----------------------------------------------------------------------------
1401 void KMMainWidget::slotNewFromTemplate(QAction *action)
1404 if (!mTemplateFolder.isValid()) {
1405 return;
1407 const Akonadi::Item item = action->data().value<Akonadi::Item>();
1408 newFromTemplate(item);
1411 //-----------------------------------------------------------------------------
1412 void KMMainWidget::newFromTemplate(const Akonadi::Item &msg)
1414 if (!msg.isValid()) {
1415 return;
1417 KMCommand *command = new KMUseTemplateCommand(this, msg);
1418 command->start();
1421 //-----------------------------------------------------------------------------
1422 void KMMainWidget::slotPostToML()
1424 if (mCurrentFolder && mCurrentFolder->isMailingListEnabled()) {
1425 if (KMail::Util::mailingListPost(mCurrentFolder)) {
1426 return;
1429 slotCompose();
1432 void KMMainWidget::slotExpireFolder()
1434 if (!mCurrentFolder) {
1435 return;
1437 bool mustDeleteExpirationAttribute = false;
1438 MailCommon::ExpireCollectionAttribute *attr = MailCommon::Util::expirationCollectionAttribute(mCurrentFolder->collection(), mustDeleteExpirationAttribute);
1439 bool canBeExpired = true;
1440 if (!attr->isAutoExpire()) {
1441 canBeExpired = false;
1442 } else if (attr->unreadExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever &&
1443 attr->readExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever) {
1444 canBeExpired = false;
1447 if (!canBeExpired) {
1448 const QString message = i18n("This folder does not have any expiry options set");
1449 KMessageBox::information(this, message);
1450 if (mustDeleteExpirationAttribute) {
1451 delete attr;
1453 return;
1456 if (KMailSettings::self()->warnBeforeExpire()) {
1457 const QString message = i18n("<qt>Are you sure you want to expire the folder <b>%1</b>?</qt>",
1458 mCurrentFolder->name().toHtmlEscaped());
1459 if (KMessageBox::warningContinueCancel(this, message, i18n("Expire Folder"),
1460 KGuiItem(i18n("&Expire")))
1461 != KMessageBox::Continue) {
1462 if (mustDeleteExpirationAttribute) {
1463 delete attr;
1465 return;
1469 MailCommon::Util::expireOldMessages(mCurrentFolder->collection(), true /*immediate*/);
1470 if (mustDeleteExpirationAttribute) {
1471 delete attr;
1475 //-----------------------------------------------------------------------------
1476 void KMMainWidget::slotEmptyFolder()
1478 if (!mCurrentFolder) {
1479 return;
1481 const bool isTrash = CommonKernel->folderIsTrash(mCurrentFolder->collection());
1482 if (KMailSettings::self()->confirmBeforeEmpty()) {
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>", mCurrentFolder->name().toHtmlEscaped());
1489 if (KMessageBox::warningContinueCancel(this, text, title, KGuiItem(title, QStringLiteral("user-trash")))
1490 != KMessageBox::Continue) {
1491 return;
1494 #ifndef QT_NO_CURSOR
1495 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
1496 #endif
1497 slotMarkAll();
1498 if (isTrash) {
1499 /* Don't ask for confirmation again when deleting, the user has already
1500 confirmed. */
1501 slotDeleteMsg(false);
1502 } else {
1503 slotTrashSelectedMessages();
1506 if (mMsgView) {
1507 mMsgView->clearCache();
1510 if (!isTrash) {
1511 BroadcastStatus::instance()->setStatusMsg(i18n("Moved all messages to the trash"));
1514 updateMessageActions();
1516 // Disable empty trash/move all to trash action - we've just deleted/moved
1517 // all folder contents.
1518 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)->setEnabled(false);
1521 //-----------------------------------------------------------------------------
1522 void KMMainWidget::slotArchiveFolder()
1524 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
1525 KMail::ArchiveFolderDialog archiveDialog;
1526 archiveDialog.setFolder(mCurrentFolder->collection());
1527 archiveDialog.exec();
1531 //-----------------------------------------------------------------------------
1532 void KMMainWidget::slotRemoveFolder()
1534 if (!mCurrentFolder) {
1535 return;
1537 if (!mCurrentFolder->collection().isValid()) {
1538 return;
1540 if (mCurrentFolder->isSystemFolder()) {
1541 return;
1543 if (mCurrentFolder->isReadOnly()) {
1544 return;
1547 RemoveCollectionJob *job = new RemoveCollectionJob(this);
1548 connect(job, &RemoveCollectionJob::clearCurrentFolder, this, &KMMainWidget::slotClearCurrentFolder);
1549 job->setMainWidget(this);
1550 job->setCurrentFolder(mCurrentFolder->collection());
1551 job->start();
1554 void KMMainWidget::slotClearCurrentFolder()
1556 mCurrentFolder.clear();
1559 //-----------------------------------------------------------------------------
1560 void KMMainWidget::slotExpireAll()
1562 if (KMailSettings::self()->warnBeforeExpire()) {
1563 const int ret = KMessageBox::warningContinueCancel(KMainWindow::memberList().first(),
1564 i18n("Are you sure you want to expire all old messages?"),
1565 i18n("Expire Old Messages?"), KGuiItem(i18n("Expire")));
1566 if (ret != KMessageBox::Continue) {
1567 return;
1571 kmkernel->expireAllFoldersNow();
1574 //-----------------------------------------------------------------------------
1575 void KMMainWidget::slotOverrideHtmlLoadExt()
1577 if (mHtmlLoadExtGlobalSetting == mFolderHtmlLoadExtPreference) {
1578 int result = KMessageBox::warningContinueCancel(this,
1579 // the warning text is taken from configuredialog.cpp:
1580 i18n("Loading external references in html mail will make you more vulnerable to "
1581 "\"spam\" and may increase the likelihood that your system will be "
1582 "compromised by other present and anticipated security exploits."),
1583 i18n("Security Warning"),
1584 KGuiItem(i18n("Load External References")),
1585 KStandardGuiItem::cancel(),
1586 QStringLiteral("OverrideHtmlLoadExtWarning"), Q_NULLPTR);
1587 if (result == KMessageBox::Cancel) {
1588 mPreferHtmlLoadExtAction->setChecked(false);
1589 return;
1592 mFolderHtmlLoadExtPreference = !mFolderHtmlLoadExtPreference;
1594 if (mMsgView) {
1595 mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
1596 mMsgView->update(true);
1600 //-----------------------------------------------------------------------------
1601 void KMMainWidget::slotMessageQueuedOrDrafted()
1603 if (!CommonKernel->folderIsDraftOrOutbox(mCurrentFolder->collection())) {
1604 return;
1606 if (mMsgView) {
1607 mMsgView->update(true);
1611 //-----------------------------------------------------------------------------
1612 void KMMainWidget::slotForwardInlineMsg()
1614 if (!mCurrentFolder) {
1615 return;
1618 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
1619 if (selectedMessages.isEmpty()) {
1620 return;
1622 KMForwardCommand *command = new KMForwardCommand(
1623 this, selectedMessages, mCurrentFolder->identity()
1626 command->start();
1629 //-----------------------------------------------------------------------------
1630 void KMMainWidget::slotForwardAttachedMsg()
1632 if (!mCurrentFolder) {
1633 return;
1636 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
1637 if (selectedMessages.isEmpty()) {
1638 return;
1640 KMForwardAttachedCommand *command = new KMForwardAttachedCommand(
1641 this, selectedMessages, mCurrentFolder->identity()
1644 command->start();
1647 //-----------------------------------------------------------------------------
1648 void KMMainWidget::slotUseTemplate()
1650 newFromTemplate(mMessagePane->currentItem());
1653 //-----------------------------------------------------------------------------
1654 void KMMainWidget::slotResendMsg()
1656 const Akonadi::Item msg = mMessagePane->currentItem();
1657 if (!msg.isValid()) {
1658 return;
1660 KMCommand *command = new KMResendMessageCommand(this, msg);
1662 command->start();
1665 //-----------------------------------------------------------------------------
1666 // Message moving and permanent deletion
1669 void KMMainWidget::moveMessageSelected(MessageList::Core::MessageItemSetReference ref, const Akonadi::Collection &dest, bool confirmOnDeletion)
1671 Akonadi::Item::List selectMsg = mMessagePane->itemListFromPersistentSet(ref);
1672 // If this is a deletion, ask for confirmation
1673 if (confirmOnDeletion) {
1674 int ret = KMessageBox::warningContinueCancel(
1675 this,
1676 i18np(
1677 "<qt>Do you really want to delete the selected message?<br />"
1678 "Once deleted, it cannot be restored.</qt>",
1679 "<qt>Do you really want to delete the %1 selected messages?<br />"
1680 "Once deleted, they cannot be restored.</qt>",
1681 selectMsg.count()
1683 selectMsg.count() > 1 ? i18n("Delete Messages") : i18n("Delete Message"),
1684 KStandardGuiItem::del(),
1685 KStandardGuiItem::cancel(),
1686 QStringLiteral("NoConfirmDelete")
1688 if (ret == KMessageBox::Cancel) {
1689 mMessagePane->deletePersistentSet(ref);
1690 return; // user canceled the action
1693 mMessagePane->markMessageItemsAsAboutToBeRemoved(ref, true);
1694 // And stuff them into a KMMoveCommand :)
1695 KMMoveCommand *command = new KMMoveCommand(dest, selectMsg, ref);
1696 QObject::connect(
1697 command, &KMMoveCommand::moveDone,
1698 this, &KMMainWidget::slotMoveMessagesCompleted
1700 command->start();
1702 if (dest.isValid()) {
1703 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages..."));
1704 } else {
1705 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages..."));
1709 void KMMainWidget::slotMoveMessagesCompleted(KMMoveCommand *command)
1711 Q_ASSERT(command);
1712 mMessagePane->markMessageItemsAsAboutToBeRemoved(command->refSet(), false);
1713 mMessagePane->deletePersistentSet(command->refSet());
1714 // Bleah :D
1715 const bool moveWasReallyADelete = !command->destFolder().isValid();
1717 if (command->result() == KMCommand::OK) {
1718 if (moveWasReallyADelete) {
1719 BroadcastStatus::instance()->setStatusMsg(i18n("Messages deleted successfully."));
1720 } else {
1721 BroadcastStatus::instance()->setStatusMsg(i18n("Messages moved successfully."));
1723 } else {
1724 if (moveWasReallyADelete) {
1725 if (command->result() == KMCommand::Failed) {
1726 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages failed."));
1727 } else {
1728 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages canceled."));
1730 } else {
1731 if (command->result() == KMCommand::Failed) {
1732 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages failed."));
1733 } else {
1734 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages canceled."));
1738 // The command will autodelete itself and will also kill the set.
1741 void KMMainWidget::slotDeleteMessages()
1743 slotDeleteMsg(true);
1746 void KMMainWidget::slotDeleteMsg(bool confirmDelete)
1748 // Create a persistent message set from the current selection
1749 MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1750 if (ref != -1) {
1751 moveMessageSelected(ref, Akonadi::Collection(), confirmDelete);
1755 void KMMainWidget::slotDeleteThread(bool confirmDelete)
1757 // Create a persistent set from the current thread.
1758 MessageList::Core::MessageItemSetReference ref = mMessagePane->currentThreadAsPersistentSet();
1759 if (ref != -1) {
1760 moveMessageSelected(ref, Akonadi::Collection(), confirmDelete);
1764 FolderSelectionDialog *KMMainWidget::moveOrCopyToDialog()
1766 if (!mMoveOrCopyToDialog) {
1767 FolderSelectionDialog::SelectionFolderOption options = FolderSelectionDialog::HideVirtualFolder;
1768 mMoveOrCopyToDialog = new FolderSelectionDialog(this, options);
1769 mMoveOrCopyToDialog->setModal(true);
1771 return mMoveOrCopyToDialog;
1774 FolderSelectionDialog *KMMainWidget::selectFromAllFoldersDialog()
1776 if (!mSelectFromAllFoldersDialog) {
1777 FolderSelectionDialog::SelectionFolderOptions options = FolderSelectionDialog::None;
1778 options |= FolderSelectionDialog::NotAllowToCreateNewFolder;
1780 mSelectFromAllFoldersDialog = new FolderSelectionDialog(this, options);
1781 mSelectFromAllFoldersDialog->setModal(true);
1783 return mSelectFromAllFoldersDialog;
1786 void KMMainWidget::slotMoveSelectedMessageToFolder()
1788 QPointer<MailCommon::FolderSelectionDialog> dialog(moveOrCopyToDialog());
1789 dialog->setWindowTitle(i18n("Move Messages to Folder"));
1790 if (dialog->exec() && dialog) {
1791 const Akonadi::Collection dest = dialog->selectedCollection();
1792 if (dest.isValid()) {
1793 moveSelectedMessagesToFolder(dest);
1798 void KMMainWidget::moveSelectedMessagesToFolder(const Akonadi::Collection &dest)
1800 MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1801 if (ref != -1) {
1802 //Need to verify if dest == src ??? akonadi do it for us.
1803 moveMessageSelected(ref, dest, false);
1807 void KMMainWidget::copyMessageSelected(const Akonadi::Item::List &selectMsg, const Akonadi::Collection &dest)
1809 if (selectMsg.isEmpty()) {
1810 return;
1812 // And stuff them into a KMCopyCommand :)
1813 KMCommand *command = new KMCopyCommand(dest, selectMsg);
1814 QObject::connect(
1815 command, &KMCommand::completed,
1816 this, &KMMainWidget::slotCopyMessagesCompleted
1818 command->start();
1819 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages..."));
1822 void KMMainWidget::slotCopyMessagesCompleted(KMCommand *command)
1824 Q_ASSERT(command);
1825 if (command->result() == KMCommand::OK) {
1826 BroadcastStatus::instance()->setStatusMsg(i18n("Messages copied successfully."));
1827 } else {
1828 if (command->result() == KMCommand::Failed) {
1829 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages failed."));
1830 } else {
1831 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages canceled."));
1834 // The command will autodelete itself and will also kill the set.
1837 void KMMainWidget::slotCopySelectedMessagesToFolder()
1839 QPointer<MailCommon::FolderSelectionDialog> dialog(moveOrCopyToDialog());
1840 dialog->setWindowTitle(i18n("Copy Messages to Folder"));
1842 if (dialog->exec() && dialog) {
1843 const Akonadi::Collection dest = dialog->selectedCollection();
1844 if (dest.isValid()) {
1845 copySelectedMessagesToFolder(dest);
1850 void KMMainWidget::copySelectedMessagesToFolder(const Akonadi::Collection &dest)
1852 const Akonadi::Item::List lstMsg = mMessagePane->selectionAsMessageItemList();
1853 if (!lstMsg.isEmpty()) {
1854 copyMessageSelected(lstMsg, dest);
1858 //-----------------------------------------------------------------------------
1859 // Message trashing
1861 void KMMainWidget::trashMessageSelected(MessageList::Core::MessageItemSetReference ref)
1863 if (!mCurrentFolder) {
1864 return;
1867 const Akonadi::Item::List select = mMessagePane->itemListFromPersistentSet(ref);
1868 mMessagePane->markMessageItemsAsAboutToBeRemoved(ref, true);
1870 // FIXME: Why we don't use KMMoveCommand( trashFolder(), selectedMessages ); ?
1871 // And stuff them into a KMTrashMsgCommand :)
1872 KMCommand *command = new KMTrashMsgCommand(mCurrentFolder->collection(), select, ref);
1874 QObject::connect(
1875 command, SIGNAL(moveDone(KMMoveCommand*)),
1876 this, SLOT(slotTrashMessagesCompleted(KMMoveCommand*))
1878 command->start();
1879 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash..."));
1882 void KMMainWidget::slotTrashMessagesCompleted(KMMoveCommand *command)
1884 Q_ASSERT(command);
1885 mMessagePane->markMessageItemsAsAboutToBeRemoved(command->refSet(), false);
1886 mMessagePane->deletePersistentSet(command->refSet());
1887 if (command->result() == KMCommand::OK) {
1888 BroadcastStatus::instance()->setStatusMsg(i18n("Messages moved to trash successfully."));
1889 } else {
1890 if (command->result() == KMCommand::Failed) {
1891 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash failed."));
1892 } else {
1893 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash canceled."));
1897 // The command will autodelete itself and will also kill the set.
1900 void KMMainWidget::slotTrashSelectedMessages()
1902 MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1903 if (ref != -1) {
1904 trashMessageSelected(ref);
1908 void KMMainWidget::slotTrashThread()
1910 MessageList::Core::MessageItemSetReference ref = mMessagePane->currentThreadAsPersistentSet();
1911 if (ref != -1) {
1912 trashMessageSelected(ref);
1916 //-----------------------------------------------------------------------------
1917 // Message tag setting for messages
1919 // FIXME: The "selection" version of these functions is in MessageActions.
1920 // We should probably move everything there....
1921 void KMMainWidget::toggleMessageSetTag(const Akonadi::Item::List &select, const Akonadi::Tag &tag)
1923 if (select.isEmpty()) {
1924 return;
1926 KMCommand *command = new KMSetTagCommand(Akonadi::Tag::List() << tag, select, KMSetTagCommand::Toggle);
1927 command->start();
1930 void KMMainWidget::slotSelectMoreMessageTagList()
1932 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
1933 if (selectedMessages.isEmpty()) {
1934 return;
1937 TagSelectDialog dlg(this, selectedMessages.count(), selectedMessages.first());
1938 dlg.setActionCollection(QList<KActionCollection *>() << actionCollection());
1939 if (dlg.exec()) {
1940 const Akonadi::Tag::List lst = dlg.selectedTag();
1941 KMCommand *command = new KMSetTagCommand(lst, selectedMessages, KMSetTagCommand::CleanExistingAndAddNew);
1942 command->start();
1946 void KMMainWidget::slotUpdateMessageTagList(const Akonadi::Tag &tag)
1948 // Create a persistent set from the current thread.
1949 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
1950 if (selectedMessages.isEmpty()) {
1951 return;
1953 toggleMessageSetTag(selectedMessages, tag);
1956 void KMMainWidget::refreshMessageListSelection()
1958 mAkonadiStandardActionManager->setItemSelectionModel(mMessagePane->currentItemSelectionModel());
1959 slotMessageSelected(mMessagePane->currentItem());
1962 //-----------------------------------------------------------------------------
1963 // Status setting for threads
1965 // FIXME: The "selection" version of these functions is in MessageActions.
1966 // We should probably move everything there....
1967 void KMMainWidget::setMessageSetStatus(const Akonadi::Item::List &select,
1968 const Akonadi::MessageStatus &status,
1969 bool toggle)
1971 KMCommand *command = new KMSetStatusCommand(status, select, toggle);
1972 command->start();
1975 void KMMainWidget::setCurrentThreadStatus(const Akonadi::MessageStatus &status, bool toggle)
1977 const Akonadi::Item::List select = mMessagePane->currentThreadAsMessageList();
1978 if (select.isEmpty()) {
1979 return;
1981 setMessageSetStatus(select, status, toggle);
1984 void KMMainWidget::slotSetThreadStatusUnread()
1986 setCurrentThreadStatus(MessageStatus::statusRead(), true);
1989 void KMMainWidget::slotSetThreadStatusImportant()
1991 setCurrentThreadStatus(MessageStatus::statusImportant(), true);
1994 void KMMainWidget::slotSetThreadStatusRead()
1996 setCurrentThreadStatus(MessageStatus::statusRead(), false);
1999 void KMMainWidget::slotSetThreadStatusToAct()
2001 setCurrentThreadStatus(MessageStatus::statusToAct(), true);
2004 void KMMainWidget::slotSetThreadStatusWatched()
2006 setCurrentThreadStatus(MessageStatus::statusWatched(), true);
2007 if (mWatchThreadAction->isChecked()) {
2008 mIgnoreThreadAction->setChecked(false);
2012 void KMMainWidget::slotSetThreadStatusIgnored()
2014 setCurrentThreadStatus(MessageStatus::statusIgnored(), true);
2015 if (mIgnoreThreadAction->isChecked()) {
2016 mWatchThreadAction->setChecked(false);
2020 //-----------------------------------------------------------------------------
2021 void KMMainWidget::slotRedirectMsg()
2023 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2024 if (selectedMessages.isEmpty()) {
2025 return;
2028 KMCommand *command = new KMRedirectCommand(this, selectedMessages);
2029 command->start();
2032 //-----------------------------------------------------------------------------
2033 void KMMainWidget::slotCustomReplyToMsg(const QString &tmpl)
2035 const Akonadi::Item msg = mMessagePane->currentItem();
2036 if (!msg.isValid()) {
2037 return;
2040 const QString text = mMsgView ? mMsgView->copyText() : QString();
2042 qCDebug(KMAIL_LOG) << "Reply with template:" << tmpl;
2044 KMCommand *command = new KMReplyCommand(this,
2045 msg,
2046 MessageComposer::ReplySmart,
2047 text, false,
2048 tmpl);
2049 command->start();
2052 //-----------------------------------------------------------------------------
2053 void KMMainWidget::slotCustomReplyAllToMsg(const QString &tmpl)
2055 const Akonadi::Item msg = mMessagePane->currentItem();
2056 if (!msg.isValid()) {
2057 return;
2060 const QString text = mMsgView ? mMsgView->copyText() : QString();
2062 qCDebug(KMAIL_LOG) << "Reply to All with template:" << tmpl;
2064 KMCommand *command = new KMReplyCommand(this,
2065 msg,
2066 MessageComposer::ReplyAll,
2067 text,
2068 false,
2069 tmpl
2072 command->start();
2075 //-----------------------------------------------------------------------------
2076 void KMMainWidget::slotCustomForwardMsg(const QString &tmpl)
2078 if (!mCurrentFolder) {
2079 return;
2082 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2083 if (selectedMessages.isEmpty()) {
2084 return;
2087 qCDebug(KMAIL_LOG) << "Forward with template:" << tmpl;
2088 KMForwardCommand *command = new KMForwardCommand(
2089 this, selectedMessages, mCurrentFolder->identity(), tmpl
2092 command->start();
2095 void KMMainWidget::openFilterDialog(const QByteArray &field, const QString &value)
2097 FilterIf->openFilterDialog(false);
2098 FilterIf->createFilter(field, value);
2101 //-----------------------------------------------------------------------------
2102 void KMMainWidget::slotSubjectFilter()
2104 const KMime::Message::Ptr msg = mMessagePane->currentMessage();
2105 if (!msg) {
2106 return;
2109 openFilterDialog("Subject", msg->subject()->asUnicodeString());
2112 //-----------------------------------------------------------------------------
2113 void KMMainWidget::slotFromFilter()
2115 KMime::Message::Ptr msg = mMessagePane->currentMessage();
2116 if (!msg) {
2117 return;
2120 AddrSpecList al = MessageHelper::extractAddrSpecs(msg, "From");
2121 if (al.empty()) {
2122 openFilterDialog("From", msg->from()->asUnicodeString());
2123 } else {
2124 openFilterDialog("From", al.front().asString());
2128 //-----------------------------------------------------------------------------
2129 void KMMainWidget::slotToFilter()
2131 KMime::Message::Ptr msg = mMessagePane->currentMessage();
2132 if (!msg) {
2133 return;
2135 openFilterDialog("To", msg->to()->asUnicodeString());
2138 void KMMainWidget::slotCcFilter()
2140 KMime::Message::Ptr msg = mMessagePane->currentMessage();
2141 if (!msg) {
2142 return;
2144 openFilterDialog("Cc", msg->cc()->asUnicodeString());
2147 void KMMainWidget::slotBandwidth(bool b)
2149 PimCommon::NetworkUtil::self()->setLowBandwidth(b);
2152 //-----------------------------------------------------------------------------
2153 void KMMainWidget::slotUndo()
2155 kmkernel->undoStack()->undo();
2156 updateMessageActions();
2157 updateFolderMenu();
2160 //-----------------------------------------------------------------------------
2161 void KMMainWidget::slotJumpToFolder()
2163 QPointer<MailCommon::FolderSelectionDialog> dialog(selectFromAllFoldersDialog());
2164 dialog->setWindowTitle(i18n("Jump to Folder"));
2165 if (dialog->exec() && dialog) {
2166 Akonadi::Collection collection = dialog->selectedCollection();
2167 if (collection.isValid()) {
2168 slotSelectCollectionFolder(collection);
2173 void KMMainWidget::slotSelectCollectionFolder(const Akonadi::Collection &col)
2175 if (mFolderTreeWidget) {
2176 mFolderTreeWidget->selectCollectionFolder(col);
2177 slotFolderChanged(col);
2181 void KMMainWidget::slotApplyFilters()
2183 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2184 if (selectedMessages.isEmpty()) {
2185 return;
2187 applyFilters(selectedMessages);
2190 void KMMainWidget::slotApplyFiltersOnFolder()
2192 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
2193 Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mCurrentFolder->collection(), this);
2194 connect(job, &Akonadi::ItemFetchJob::result, this, &KMMainWidget::slotFetchItemsForFolderDone);
2198 void KMMainWidget::slotFetchItemsForFolderDone(KJob *job)
2200 Akonadi::ItemFetchJob *fjob = dynamic_cast<Akonadi::ItemFetchJob *>(job);
2201 Q_ASSERT(fjob);
2202 Akonadi::Item::List items = fjob->items();
2203 applyFilters(items);
2206 void KMMainWidget::applyFilters(const Akonadi::Item::List &selectedMessages)
2208 #ifndef QT_NO_CURSOR
2209 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
2210 #endif
2212 MailCommon::FilterManager::instance()->filter(selectedMessages);
2215 //-----------------------------------------------------------------------------
2216 void KMMainWidget::slotCheckVacation()
2218 updateVacationScriptStatus(false);
2219 if (!kmkernel->askToGoOnline()) {
2220 return;
2223 mVacationManager->checkVacation();
2224 connect(mVacationManager, SIGNAL(updateVacationScriptStatus(bool,QString)), SLOT(updateVacationScriptStatus(bool,QString)));
2225 connect(mVacationManager, SIGNAL(editVacation()), SLOT(slotEditVacation()));
2228 void KMMainWidget::slotEditVacation(const QString &serverName)
2230 if (!kmkernel->askToGoOnline()) {
2231 return;
2234 mVacationManager->slotEditVacation(serverName);
2237 //-----------------------------------------------------------------------------
2238 void KMMainWidget::slotDebugSieve()
2240 #if !defined(NDEBUG)
2241 if (mSieveDebugDialog) {
2242 return;
2245 mSieveDebugDialog = new KSieveUi::SieveDebugDialog(this);
2246 mSieveDebugDialog->exec();
2247 delete mSieveDebugDialog;
2248 #endif
2251 void KMMainWidget::slotConfigChanged()
2253 readConfig();
2254 mMsgActions->setupForwardActions(actionCollection());
2255 mMsgActions->setupForwardingActionsList(mGUIClient);
2258 //-----------------------------------------------------------------------------
2259 void KMMainWidget::slotSaveMsg()
2261 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2262 if (selectedMessages.isEmpty()) {
2263 return;
2265 KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand(this, selectedMessages);
2266 saveCommand->start();
2269 //-----------------------------------------------------------------------------
2270 void KMMainWidget::slotOpenMsg()
2272 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand(this, QUrl(), overrideEncoding(), this);
2274 openCommand->start();
2277 //-----------------------------------------------------------------------------
2278 void KMMainWidget::slotSaveAttachments()
2280 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2281 if (selectedMessages.isEmpty()) {
2282 return;
2284 // Avoid re-downloading in the common case that only one message is selected, and the message
2285 // is also displayed in the viewer. For this, create a dummy item without a parent collection / item id,
2286 // so that KMCommand doesn't download it.
2287 KMSaveAttachmentsCommand *saveCommand = Q_NULLPTR;
2288 if (mMsgView && selectedMessages.size() == 1 &&
2289 mMsgView->message().hasPayload<KMime::Message::Ptr>() &&
2290 selectedMessages.first().id() == mMsgView->message().id()) {
2291 Akonadi::Item dummyItem;
2292 dummyItem.setPayload<KMime::Message::Ptr>(mMsgView->message().payload<KMime::Message::Ptr>());
2293 saveCommand = new KMSaveAttachmentsCommand(this, dummyItem, mMsgView->viewer());
2294 } else {
2295 saveCommand = new KMSaveAttachmentsCommand(this, selectedMessages);
2298 saveCommand->start();
2301 void KMMainWidget::slotOnlineStatus()
2303 // KMKernel will Q_EMIT a signal when we toggle the network state that is caught by
2304 // KMMainWidget::slotUpdateOnlineStatus to update our GUI
2305 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Online) {
2306 // if online; then toggle and set it offline.
2307 kmkernel->stopNetworkJobs();
2308 } else {
2309 kmkernel->resumeNetworkJobs();
2310 slotCheckVacation();
2314 void KMMainWidget::slotUpdateOnlineStatus(KMailSettings::EnumNetworkState::type)
2316 if (!mAkonadiStandardActionManager) {
2317 return;
2319 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::ToggleWorkOffline);
2320 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Online) {
2321 action->setText(i18n("Work Offline"));
2322 action->setIcon(QIcon::fromTheme(QStringLiteral("user-offline")));
2323 } else {
2324 action->setText(i18n("Work Online"));
2325 action->setIcon(QIcon::fromTheme(QStringLiteral("user-online")));
2329 //-----------------------------------------------------------------------------
2330 void KMMainWidget::slotSendQueued()
2332 if (kmkernel->msgSender()) {
2333 kmkernel->msgSender()->sendQueued();
2337 //-----------------------------------------------------------------------------
2338 void KMMainWidget::slotSendQueuedVia(MailTransport::Transport *transport)
2340 if (transport) {
2341 if (kmkernel->msgSender()) {
2342 kmkernel->msgSender()->sendQueued(transport->id());
2347 //-----------------------------------------------------------------------------
2348 void KMMainWidget::slotShowBusySplash()
2350 if (mReaderWindowActive) {
2351 mMsgView->displayBusyPage();
2355 void KMMainWidget::showOfflinePage()
2357 if (!mReaderWindowActive) {
2358 return;
2361 mMsgView->displayOfflinePage();
2364 void KMMainWidget::showResourceOfflinePage()
2366 if (!mReaderWindowActive) {
2367 return;
2370 mMsgView->displayResourceOfflinePage();
2373 //-----------------------------------------------------------------------------
2374 void KMMainWidget::slotReplaceMsgByUnencryptedVersion()
2376 qCDebug(KMAIL_LOG);
2377 Akonadi::Item oldMsg = mMessagePane->currentItem();
2378 if (oldMsg.isValid()) {
2379 #if 0
2380 qCDebug(KMAIL_LOG) << "Old message found";
2381 if (oldMsg->hasUnencryptedMsg()) {
2382 qCDebug(KMAIL_LOG) << "Extra unencrypted message found";
2383 KMime::Message *newMsg = oldMsg->unencryptedMsg();
2384 // adjust the message id
2386 QString msgId(oldMsg->msgId());
2387 QString prefix("DecryptedMsg.");
2388 int oldIdx = msgId.indexOf(prefix, 0, Qt::CaseInsensitive);
2389 if (-1 == oldIdx) {
2390 int leftAngle = msgId.lastIndexOf('<');
2391 msgId = msgId.insert((-1 == leftAngle) ? 0 : ++leftAngle, prefix);
2392 } else {
2393 // toggle between "DecryptedMsg." and "DeCryptedMsg."
2394 // to avoid same message id
2395 QCharRef c = msgId[ oldIdx + 2 ];
2396 if ('C' == c) {
2397 c = 'c';
2398 } else {
2399 c = 'C';
2402 newMsg->setMsgId(msgId);
2403 mMsgView->setIdOfLastViewedMessage(msgId);
2405 // insert the unencrypted message
2406 qCDebug(KMAIL_LOG) << "Adding unencrypted message to folder";
2407 mFolder->addMsg(newMsg);
2408 /* Figure out its index in the folder for selecting. This must be count()-1,
2409 * since we append. Be safe and do find, though, just in case. */
2410 int newMsgIdx = mFolder->find(newMsg);
2411 Q_ASSERT(newMsgIdx != -1);
2412 /* we need this unget, to have the message displayed correctly initially */
2413 mFolder->unGetMsg(newMsgIdx);
2414 int idx = mFolder->find(oldMsg);
2415 Q_ASSERT(idx != -1);
2416 /* only select here, so the old one is not un-Gotten before, which would
2417 * render the pointer we hold invalid so that find would fail */
2418 #if 0
2419 // FIXME (Pragma)
2420 mHeaders->setCurrentItemByIndex(newMsgIdx);
2421 #endif
2422 // remove the old one
2423 if (idx != -1) {
2424 qCDebug(KMAIL_LOG) << "Deleting encrypted message";
2425 mFolder->take(idx);
2428 qCDebug(KMAIL_LOG) << "Updating message actions";
2429 updateMessageActions();
2431 qCDebug(KMAIL_LOG) << "Done.";
2432 } else {
2433 qCDebug(KMAIL_LOG) << "NO EXTRA UNENCRYPTED MESSAGE FOUND";
2435 #else
2436 qCDebug(KMAIL_LOG) << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO;
2437 #endif
2438 } else {
2439 qCDebug(KMAIL_LOG) << "PANIC: NO OLD MESSAGE FOUND";
2443 void KMMainWidget::slotFocusOnNextMessage()
2445 mMessagePane->focusNextMessageItem(MessageList::Core::MessageTypeAny, true, false);
2448 void KMMainWidget::slotFocusOnPrevMessage()
2450 mMessagePane->focusPreviousMessageItem(MessageList::Core::MessageTypeAny, true, false);
2453 void KMMainWidget::slotSelectFirstMessage()
2455 mMessagePane->selectFirstMessageItem(MessageList::Core::MessageTypeAny, true);
2458 void KMMainWidget::slotSelectLastMessage()
2460 mMessagePane->selectLastMessageItem(MessageList::Core::MessageTypeAny, true);
2463 void KMMainWidget::slotSelectFocusedMessage()
2465 mMessagePane->selectFocusedMessageItem(true);
2468 void KMMainWidget::slotSelectNextMessage()
2470 mMessagePane->selectNextMessageItem(MessageList::Core::MessageTypeAny,
2471 MessageList::Core::ClearExistingSelection,
2472 true, false);
2475 void KMMainWidget::slotExtendSelectionToNextMessage()
2477 mMessagePane->selectNextMessageItem(
2478 MessageList::Core::MessageTypeAny,
2479 MessageList::Core::GrowOrShrinkExistingSelection,
2480 true, // center item
2481 false // don't loop in folder
2485 void KMMainWidget::slotSelectNextUnreadMessage()
2487 // The looping logic is: "Don't loop" just never loops, "Loop in current folder"
2488 // loops just in current folder, "Loop in all folders" loops in the current folder
2489 // first and then after confirmation jumps to the next folder.
2490 // A bad point here is that if you answer "No, and don't ask me again" to the confirmation
2491 // dialog then you have "Loop in current folder" and "Loop in all folders" that do
2492 // the same thing and no way to get the old behaviour. However, after a consultation on #kontact,
2493 // for bug-to-bug backward compatibility, the masters decided to keep it b0rken :D
2494 // If nobody complains, it stays like it is: if you complain enough maybe the masters will
2495 // decide to reconsider :)
2496 if (!mMessagePane->selectNextMessageItem(
2497 MessageList::Core::MessageTypeUnreadOnly,
2498 MessageList::Core::ClearExistingSelection,
2499 true, // center item
2500 KMailSettings::self()->loopOnGotoUnread() != KMailSettings::EnumLoopOnGotoUnread::DontLoop
2501 )) {
2502 // no next unread message was found in the current folder
2503 if ((KMailSettings::self()->loopOnGotoUnread() ==
2504 KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders) ||
2505 (KMailSettings::self()->loopOnGotoUnread() ==
2506 KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders)) {
2507 mGoToFirstUnreadMessageInSelectedFolder = true;
2508 mFolderTreeWidget->folderTreeView()->selectNextUnreadFolder(true);
2509 mGoToFirstUnreadMessageInSelectedFolder = false;
2514 void KMMainWidget::slotSelectPreviousMessage()
2516 mMessagePane->selectPreviousMessageItem(MessageList::Core::MessageTypeAny,
2517 MessageList::Core::ClearExistingSelection,
2518 true, false);
2521 void KMMainWidget::slotExtendSelectionToPreviousMessage()
2523 mMessagePane->selectPreviousMessageItem(
2524 MessageList::Core::MessageTypeAny,
2525 MessageList::Core::GrowOrShrinkExistingSelection,
2526 true, // center item
2527 false // don't loop in folder
2531 void KMMainWidget::slotSelectPreviousUnreadMessage()
2533 if (!mMessagePane->selectPreviousMessageItem(
2534 MessageList::Core::MessageTypeUnreadOnly,
2535 MessageList::Core::ClearExistingSelection,
2536 true, // center item
2537 KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInCurrentFolder
2538 )) {
2539 // no next unread message was found in the current folder
2540 if ((KMailSettings::self()->loopOnGotoUnread() ==
2541 KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders) ||
2542 (KMailSettings::self()->loopOnGotoUnread() ==
2543 KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders)) {
2544 mGoToFirstUnreadMessageInSelectedFolder = true;
2545 mFolderTreeWidget->folderTreeView()->selectPrevUnreadFolder();
2546 mGoToFirstUnreadMessageInSelectedFolder = false;
2551 void KMMainWidget::slotDisplayCurrentMessage()
2553 if (mMessagePane->currentItem().isValid() && !mMessagePane->searchEditHasFocus()) {
2554 slotMessageActivated(mMessagePane->currentItem());
2558 // Called by double-clicked or 'Enter' in the messagelist -> pop up reader window
2559 void KMMainWidget::slotMessageActivated(const Akonadi::Item &msg)
2561 if (!mCurrentFolder || !msg.isValid()) {
2562 return;
2565 if (CommonKernel->folderIsDraftOrOutbox(mCurrentFolder->collection())) {
2566 mMsgActions->setCurrentMessage(msg);
2567 mMsgActions->editCurrentMessage();
2568 return;
2571 if (CommonKernel->folderIsTemplates(mCurrentFolder->collection())) {
2572 slotUseTemplate();
2573 return;
2576 // Try to fetch the mail, even in offline mode, it might be cached
2577 KMFetchMessageCommand *cmd = new KMFetchMessageCommand(this, msg);
2578 connect(cmd, &KMCommand::completed,
2579 this, &KMMainWidget::slotItemsFetchedForActivation);
2580 cmd->start();
2583 void KMMainWidget::slotItemsFetchedForActivation(KMCommand *command)
2585 KMCommand::Result result = command->result();
2586 if (result != KMCommand::OK) {
2587 qCDebug(KMAIL_LOG) << "Result:" << result;
2588 return;
2591 KMFetchMessageCommand *fetchCmd = qobject_cast<KMFetchMessageCommand *>(command);
2592 const Item msg = fetchCmd->item();
2594 KMReaderMainWin *win = new KMReaderMainWin(mFolderDisplayFormatPreference, mFolderHtmlLoadExtPreference);
2595 const bool useFixedFont = mMsgView ? mMsgView->isFixedFont() :
2596 MessageViewer::MessageViewerSettings::self()->useFixedFont();
2597 win->setUseFixedFont(useFixedFont);
2599 const Akonadi::Collection parentCollection = MailCommon::Util::parentCollectionFromItem(msg);
2600 win->showMessage(overrideEncoding(), msg, parentCollection);
2601 win->show();
2604 void KMMainWidget::slotMessageStatusChangeRequest(const Akonadi::Item &item, const Akonadi::MessageStatus &set, const Akonadi::MessageStatus &clear)
2606 if (!item.isValid()) {
2607 return;
2610 if (clear.toQInt32() != Akonadi::MessageStatus().toQInt32()) {
2611 KMCommand *command = new KMSetStatusCommand(clear, Akonadi::Item::List() << item, true);
2612 command->start();
2615 if (set.toQInt32() != Akonadi::MessageStatus().toQInt32()) {
2616 KMCommand *command = new KMSetStatusCommand(set, Akonadi::Item::List() << item, false);
2617 command->start();
2621 //-----------------------------------------------------------------------------
2622 void KMMainWidget::slotMarkAll()
2624 mMessagePane->selectAll();
2625 updateMessageActions();
2628 void KMMainWidget::slotMessagePopup(const Akonadi::Item &msg, const QUrl &aUrl, const QUrl &imageUrl, const QPoint &aPoint)
2630 updateMessageMenu();
2632 const QString email = KEmailAddress::firstEmailAddress(aUrl.path()).toLower();
2633 if (aUrl.scheme() == QLatin1String("mailto") && !email.isEmpty()) {
2634 Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob(this);
2635 job->setLimit(1);
2636 job->setQuery(Akonadi::ContactSearchJob::Email, email, Akonadi::ContactSearchJob::ExactMatch);
2637 job->setProperty("msg", QVariant::fromValue(msg));
2638 job->setProperty("point", aPoint);
2639 job->setProperty("imageUrl", imageUrl);
2640 job->setProperty("url", aUrl);
2641 connect(job, &Akonadi::ContactSearchJob::result, this, &KMMainWidget::slotContactSearchJobForMessagePopupDone);
2642 } else {
2643 showMessagePopup(msg, aUrl, imageUrl, aPoint, false, false);
2647 void KMMainWidget::slotContactSearchJobForMessagePopupDone(KJob *job)
2649 const Akonadi::ContactSearchJob *searchJob = qobject_cast<Akonadi::ContactSearchJob *>(job);
2650 const bool contactAlreadyExists = !searchJob->contacts().isEmpty();
2652 const Akonadi::Item::List listContact = searchJob->items();
2653 const bool uniqueContactFound = (listContact.count() == 1);
2654 if (uniqueContactFound) {
2655 mMsgView->setContactItem(listContact.first(), searchJob->contacts().at(0));
2656 } else {
2657 mMsgView->clearContactItem();
2659 const Akonadi::Item msg = job->property("msg").value<Akonadi::Item>();
2660 const QPoint aPoint = job->property("point").toPoint();
2661 const QUrl imageUrl = job->property("imageUrl").toUrl();
2662 const QUrl url = job->property("url").toUrl();
2664 showMessagePopup(msg, url, imageUrl, aPoint, contactAlreadyExists, uniqueContactFound);
2667 void KMMainWidget::showMessagePopup(const Akonadi::Item &msg, const QUrl &url, const QUrl &imageUrl, const QPoint &aPoint, bool contactAlreadyExists, bool uniqueContactFound)
2669 QMenu *menu = new QMenu;
2671 bool urlMenuAdded = false;
2673 if (!url.isEmpty()) {
2674 if (url.scheme() == QLatin1String("mailto")) {
2675 // popup on a mailto URL
2676 menu->addAction(mMsgView->mailToComposeAction());
2677 menu->addAction(mMsgView->mailToReplyAction());
2678 menu->addAction(mMsgView->mailToForwardAction());
2680 menu->addSeparator();
2682 if (contactAlreadyExists) {
2683 if (uniqueContactFound) {
2684 menu->addAction(mMsgView->editContactAction());
2685 } else {
2686 menu->addAction(mMsgView->openAddrBookAction());
2688 } else {
2689 menu->addAction(mMsgView->addAddrBookAction());
2690 menu->addAction(mMsgView->addToExistingContactAction());
2692 menu->addSeparator();
2693 menu->addMenu(mMsgView->viewHtmlOption());
2694 menu->addSeparator();
2695 menu->addAction(mMsgView->copyURLAction());
2696 urlMenuAdded = true;
2697 } else if (url.scheme() != QLatin1String("attachment")) {
2698 // popup on a not-mailto URL
2699 menu->addAction(mMsgView->urlOpenAction());
2700 menu->addAction(mMsgView->addBookmarksAction());
2701 menu->addAction(mMsgView->urlSaveAsAction());
2702 menu->addAction(mMsgView->copyURLAction());
2703 menu->addSeparator();
2704 menu->addAction(mMsgView->shareServiceUrlMenu());
2705 if (mMsgView->isAShortUrl(url)) {
2706 menu->addSeparator();
2707 menu->addAction(mMsgView->expandShortUrlAction());
2709 if (!imageUrl.isEmpty()) {
2710 menu->addSeparator();
2711 menu->addAction(mMsgView->copyImageLocation());
2712 menu->addAction(mMsgView->downloadImageToDiskAction());
2713 menu->addAction(mMsgView->shareImage());
2714 if (mMsgView->adblockEnabled()) {
2715 menu->addSeparator();
2716 menu->addAction(mMsgView->blockImage());
2719 urlMenuAdded = true;
2721 qCDebug(KMAIL_LOG) << "URL is:" << url;
2723 const QString selectedText = mMsgView ? mMsgView->copyText() : QString();
2724 if (mMsgView && !selectedText.isEmpty()) {
2725 if (urlMenuAdded) {
2726 menu->addSeparator();
2728 menu->addAction(mMsgActions->replyMenu());
2729 menu->addSeparator();
2731 menu->addAction(mMsgView->copyAction());
2732 menu->addAction(mMsgView->selectAllAction());
2733 menu->addSeparator();
2734 mMsgActions->addWebShortcutsMenu(menu, selectedText);
2735 menu->addSeparator();
2736 menu->addActions(mMsgView->viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedSelection));
2737 if (KPIMTextEdit::TextToSpeech::self()->isReady()) {
2738 menu->addSeparator();
2739 menu->addAction(mMsgView->speakTextAction());
2741 } else if (!urlMenuAdded) {
2742 // popup somewhere else (i.e., not a URL) on the message
2743 if (!mMessagePane->currentMessage()) {
2744 // no messages
2745 delete menu;
2746 return;
2748 Akonadi::Collection parentCol = msg.parentCollection();
2749 if (parentCol.isValid() && CommonKernel->folderIsTemplates(parentCol)) {
2750 menu->addAction(mUseAction);
2751 } else {
2752 menu->addAction(mMsgActions->replyMenu());
2753 menu->addAction(mMsgActions->forwardMenu());
2755 if (parentCol.isValid() && CommonKernel->folderIsSentMailFolder(parentCol)) {
2756 menu->addAction(sendAgainAction());
2757 } else {
2758 menu->addAction(editAction());
2760 menu->addAction(mailingListActionMenu());
2761 menu->addSeparator();
2763 menu->addAction(mCopyActionMenu);
2764 menu->addAction(mMoveActionMenu);
2766 menu->addSeparator();
2768 menu->addAction(mMsgActions->messageStatusMenu());
2769 menu->addSeparator();
2770 if (mMsgView) {
2771 if (!imageUrl.isEmpty()) {
2772 menu->addSeparator();
2773 menu->addAction(mMsgView->copyImageLocation());
2774 menu->addAction(mMsgView->downloadImageToDiskAction());
2775 menu->addAction(mMsgView->shareImage());
2776 menu->addSeparator();
2777 if (mMsgView->adblockEnabled()) {
2778 menu->addAction(mMsgView->blockImage());
2779 menu->addSeparator();
2782 menu->addAction(mMsgView->viewSourceAction());
2783 menu->addAction(mMsgView->toggleFixFontAction());
2784 menu->addAction(mMsgView->toggleMimePartTreeAction());
2786 menu->addSeparator();
2787 if (mMsgActions->printPreviewAction()) {
2788 menu->addAction(mMsgActions->printPreviewAction());
2790 menu->addAction(mMsgActions->printAction());
2791 menu->addAction(mSaveAsAction);
2792 menu->addAction(mSaveAttachmentsAction);
2793 menu->addSeparator();
2794 if (parentCol.isValid() && CommonKernel->folderIsTrash(parentCol)) {
2795 menu->addAction(mDeleteAction);
2796 } else {
2797 menu->addAction(akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash));
2799 menu->addSeparator();
2801 if (mMsgView) {
2802 menu->addActions(mMsgView->viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedMessage));
2803 menu->addSeparator();
2804 menu->addAction(mMsgView->saveMessageDisplayFormatAction());
2805 menu->addAction(mMsgView->resetMessageDisplayFormatAction());
2806 menu->addSeparator();
2808 menu->addAction(mMsgActions->annotateAction());
2810 if (mMsgView && mMsgView->adblockEnabled()) {
2811 menu->addSeparator();
2812 menu->addAction(mMsgView->openBlockableItems());
2814 menu->addSeparator();
2815 menu->addAction(mMsgActions->addFollowupReminderAction());
2816 if (kmkernel->allowToDebugBalooSupport()) {
2817 menu->addSeparator();
2818 menu->addAction(mMsgActions->debugBalooAction());
2821 KAcceleratorManager::manage(menu);
2822 menu->exec(aPoint, Q_NULLPTR);
2823 delete menu;
2826 void KMMainWidget::setupActions()
2828 mMsgActions = new KMail::MessageActions(actionCollection(), this);
2829 mMsgActions->setMessageView(mMsgView);
2831 //----- File Menu
2832 mSaveAsAction = new QAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save &As..."), this);
2833 actionCollection()->addAction(QStringLiteral("file_save_as"), mSaveAsAction);
2834 connect(mSaveAsAction, &QAction::triggered, this, &KMMainWidget::slotSaveMsg);
2835 actionCollection()->setDefaultShortcut(mSaveAsAction, KStandardShortcut::save().first());
2837 mOpenAction = KStandardAction::open(this, SLOT(slotOpenMsg()),
2838 actionCollection());
2840 mOpenRecentAction = KStandardAction::openRecent(this, SLOT(slotOpenRecentMsg(QUrl)),
2841 actionCollection());
2842 KConfigGroup grp = mConfig->group(QStringLiteral("Recent Files"));
2843 mOpenRecentAction->loadEntries(grp);
2846 QAction *action = new QAction(i18n("&Expire All Folders"), this);
2847 actionCollection()->addAction(QStringLiteral("expire_all_folders"), action);
2848 connect(action, &QAction::triggered, this, &KMMainWidget::slotExpireAll);
2851 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("mail-receive")), i18n("Check &Mail"), this);
2852 actionCollection()->addAction(QStringLiteral("check_mail"), action);
2853 connect(action, &QAction::triggered, this, &KMMainWidget::slotCheckMail);
2854 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_L));
2857 KActionMenuAccount *actActionMenu = new KActionMenuAccount(this);
2858 actActionMenu->setIcon(QIcon::fromTheme(QStringLiteral("mail-receive")));
2859 actActionMenu->setText(i18n("Check Mail In"));
2861 actActionMenu->setIconText(i18n("Check Mail"));
2862 actActionMenu->setToolTip(i18n("Check Mail"));
2863 actionCollection()->addAction(QStringLiteral("check_mail_in"), actActionMenu);
2864 connect(actActionMenu, &KActionMenu::triggered, this, &KMMainWidget::slotCheckMail);
2866 mSendQueued = new QAction(QIcon::fromTheme(QStringLiteral("mail-send")), i18n("&Send Queued Messages"), this);
2867 actionCollection()->addAction(QStringLiteral("send_queued"), mSendQueued);
2868 connect(mSendQueued, &QAction::triggered, this, &KMMainWidget::slotSendQueued);
2871 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::ToggleWorkOffline);
2872 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardActionManager::ToggleWorkOffline);
2873 action->setCheckable(false);
2874 connect(action, &QAction::triggered, this, &KMMainWidget::slotOnlineStatus);
2875 action->setText(i18n("Online status (unknown)"));
2878 mSendActionMenu = new KActionMenuTransport(this);
2879 mSendActionMenu->setIcon(QIcon::fromTheme(QStringLiteral("mail-send-via")));
2880 mSendActionMenu->setText(i18n("Send Queued Messages Via"));
2881 actionCollection()->addAction(QStringLiteral("send_queued_via"), mSendActionMenu);
2883 connect(mSendActionMenu, &KActionMenuTransport::transportSelected, this, &KMMainWidget::slotSendQueuedVia);
2885 //----- Tools menu
2886 if (parent()->inherits("KMMainWin")) {
2887 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("x-office-address-book")), i18n("&Address Book"), this);
2888 actionCollection()->addAction(QStringLiteral("addressbook"), action);
2889 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotAddrBook);
2890 if (QStandardPaths::findExecutable(QStringLiteral("kaddressbook")).isEmpty()) {
2891 action->setEnabled(false);
2896 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("pgp-keys")), i18n("Certificate Manager"), this);
2897 actionCollection()->addAction(QStringLiteral("tools_start_certman"), action);
2898 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotStartCertManager);
2899 // disable action if no certman binary is around
2900 if (QStandardPaths::findExecutable(QStringLiteral("kleopatra")).isEmpty()) {
2901 action->setEnabled(false);
2905 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("pgp-keys")), i18n("GnuPG Log Viewer"), this);
2906 actionCollection()->addAction(QStringLiteral("tools_start_kwatchgnupg"), action);
2907 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotStartWatchGnuPG);
2908 #ifdef Q_OS_WIN32
2909 // not ported yet, underlying infrastructure missing on Windows
2910 const bool usableKWatchGnupg = false;
2911 #else
2912 // disable action if no kwatchgnupg binary is around
2913 bool usableKWatchGnupg = !QStandardPaths::findExecutable(QStringLiteral("kwatchgnupg")).isEmpty();
2914 #endif
2915 action->setEnabled(usableKWatchGnupg);
2918 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("document-import")), i18n("&Import Messages..."), this);
2919 actionCollection()->addAction(QStringLiteral("import"), action);
2920 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotImport);
2921 if (QStandardPaths::findExecutable(QStringLiteral("importwizard")).isEmpty()) {
2922 action->setEnabled(false);
2926 #if !defined(NDEBUG)
2928 QAction *action = new QAction(i18n("&Debug Sieve..."), this);
2929 actionCollection()->addAction(QStringLiteral("tools_debug_sieve"), action);
2930 connect(action, &QAction::triggered, this, &KMMainWidget::slotDebugSieve);
2932 #endif
2935 QAction *action = new QAction(i18n("Filter &Log Viewer..."), this);
2936 actionCollection()->addAction(QStringLiteral("filter_log_viewer"), action);
2937 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotFilterLogViewer);
2940 QAction *action = new QAction(i18n("&Anti-Spam Wizard..."), this);
2941 actionCollection()->addAction(QStringLiteral("antiSpamWizard"), action);
2942 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotAntiSpamWizard);
2945 QAction *action = new QAction(i18n("&Anti-Virus Wizard..."), this);
2946 actionCollection()->addAction(QStringLiteral("antiVirusWizard"), action);
2947 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotAntiVirusWizard);
2950 QAction *action = new QAction(i18n("&Account Wizard..."), this);
2951 actionCollection()->addAction(QStringLiteral("accountWizard"), action);
2952 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotAccountWizard);
2955 QAction *action = new QAction(i18n("&Import Wizard..."), this);
2956 actionCollection()->addAction(QStringLiteral("importWizard"), action);
2957 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotImportWizard);
2959 if (KSieveUi::Util::allowOutOfOfficeSettings()) {
2960 QAction *action = new QAction(i18n("Edit \"Out of Office\" Replies..."), this);
2961 actionCollection()->addAction(QStringLiteral("tools_edit_vacation"), action);
2962 connect(action, SIGNAL(triggered(bool)), SLOT(slotEditVacation()));
2966 QAction *action = new QAction(i18n("&Configure Automatic Archiving..."), this);
2967 actionCollection()->addAction(QStringLiteral("tools_automatic_archiving"), action);
2968 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotConfigureAutomaticArchiving);
2972 QAction *action = new QAction(i18n("Delayed Messages..."), this);
2973 actionCollection()->addAction(QStringLiteral("message_delayed"), action);
2974 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotConfigureSendLater);
2978 QAction *action = new QAction(i18n("Followup Reminder Messages..."), this);
2979 actionCollection()->addAction(QStringLiteral("followup_reminder_messages"), action);
2980 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotConfigureFollowupReminder);
2983 // Disable the standard action delete key sortcut.
2984 QAction *const standardDelAction = akonadiStandardAction(Akonadi::StandardActionManager::DeleteItems);
2985 standardDelAction->setShortcut(QKeySequence());
2987 //----- Edit Menu
2989 /* The delete action is nowhere in the gui, by default, so we need to make
2990 * sure it is plugged into the KAccel now, since that won't happen on
2991 * XMLGui construction or manual ->plug(). This is only a problem when run
2992 * as a part, though. */
2993 mDeleteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@action Hard delete, bypassing trash", "&Delete"), this);
2994 actionCollection()->addAction(QStringLiteral("delete"), mDeleteAction);
2995 connect(mDeleteAction, &QAction::triggered, this, &KMMainWidget::slotDeleteMessages);
2996 actionCollection()->setDefaultShortcut(mDeleteAction, QKeySequence(Qt::SHIFT + Qt::Key_Delete));
2998 mTrashThreadAction = new QAction(i18n("M&ove Thread to Trash"), this);
2999 actionCollection()->addAction(QStringLiteral("move_thread_to_trash"), mTrashThreadAction);
3000 actionCollection()->setDefaultShortcut(mTrashThreadAction, QKeySequence(Qt::CTRL + Qt::Key_Delete));
3001 mTrashThreadAction->setIcon(QIcon::fromTheme(QStringLiteral("user-trash")));
3002 KMail::Util::addQActionHelpText(mTrashThreadAction, i18n("Move thread to trashcan"));
3003 connect(mTrashThreadAction, &QAction::triggered, this, &KMMainWidget::slotTrashThread);
3005 mDeleteThreadAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete T&hread"), this);
3006 actionCollection()->addAction(QStringLiteral("delete_thread"), mDeleteThreadAction);
3007 //Don't use new connect api.
3008 connect(mDeleteThreadAction, SIGNAL(triggered(bool)), this, SLOT(slotDeleteThread()));
3009 actionCollection()->setDefaultShortcut(mDeleteThreadAction, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete));
3011 mSearchMessages = new QAction(QIcon::fromTheme(QStringLiteral("edit-find-mail")), i18n("&Find Messages..."), this);
3012 actionCollection()->addAction(QStringLiteral("search_messages"), mSearchMessages);
3013 connect(mSearchMessages, &QAction::triggered, this, &KMMainWidget::slotRequestFullSearchFromQuickSearch);
3014 actionCollection()->setDefaultShortcut(mSearchMessages, QKeySequence(Qt::Key_S));
3017 QAction *action = new QAction(i18n("Select &All Messages"), this);
3018 actionCollection()->addAction(QStringLiteral("mark_all_messages"), action);
3019 connect(action, &QAction::triggered, this, &KMMainWidget::slotMarkAll);
3020 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_A));
3023 //----- Folder Menu
3025 mFolderMailingListPropertiesAction = new QAction(i18n("&Mailing List Management..."), this);
3026 actionCollection()->addAction(QStringLiteral("folder_mailinglist_properties"), mFolderMailingListPropertiesAction);
3027 connect(mFolderMailingListPropertiesAction, &QAction::triggered, mManageShowCollectionProperties, &ManageShowCollectionProperties::slotFolderMailingListProperties);
3028 // mFolderMailingListPropertiesAction->setIcon(QIcon::fromTheme("document-properties-mailing-list"));
3030 mShowFolderShortcutDialogAction = new QAction(QIcon::fromTheme(QStringLiteral("configure-shortcuts")), i18n("&Assign Shortcut..."), this);
3031 actionCollection()->addAction(QStringLiteral("folder_shortcut_command"), mShowFolderShortcutDialogAction);
3032 connect(mShowFolderShortcutDialogAction, &QAction::triggered, mManageShowCollectionProperties,
3033 &ManageShowCollectionProperties::slotShowFolderShortcutDialog);
3034 // FIXME: this action is not currently enabled in the rc file, but even if
3035 // it were there is inconsistency between the action name and action.
3036 // "Expiration Settings" implies that this will lead to a settings dialogue
3037 // and it should be followed by a "...", but slotExpireFolder() performs
3038 // an immediate expiry.
3040 // TODO: expire action should be disabled if there is no content or if
3041 // the folder can't delete messages.
3043 // Leaving the action here for the moment, it and the "Expire" option in the
3044 // folder popup menu should be combined or at least made consistent. Same for
3045 // slotExpireFolder() and FolderViewItem::slotShowExpiryProperties().
3046 mExpireFolderAction = new QAction(i18n("&Expiration Settings"), this);
3047 actionCollection()->addAction(QStringLiteral("expire"), mExpireFolderAction);
3048 connect(mExpireFolderAction, &QAction::triggered, this, &KMMainWidget::slotExpireFolder);
3050 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardMailActionManager::MoveToTrash);
3051 connect(mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveToTrash), &QAction::triggered, this, &KMMainWidget::slotTrashSelectedMessages);
3053 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardMailActionManager::MoveAllToTrash);
3054 connect(mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash), &QAction::triggered, this, &KMMainWidget::slotEmptyFolder);
3056 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardActionManager::DeleteCollections);
3057 connect(mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::DeleteCollections), &QAction::triggered, this, &KMMainWidget::slotRemoveFolder);
3059 // ### PORT ME: Add this to the context menu. Not possible right now because
3060 // the context menu uses XMLGUI, and that would add the entry to
3061 // all collection context menus
3062 mArchiveFolderAction = new QAction(i18n("&Archive Folder..."), this);
3063 actionCollection()->addAction(QStringLiteral("archive_folder"), mArchiveFolderAction);
3064 connect(mArchiveFolderAction, &QAction::triggered, this, &KMMainWidget::slotArchiveFolder);
3066 mDisplayMessageFormatMenu = new DisplayMessageFormatActionMenu(this);
3067 connect(mDisplayMessageFormatMenu, &DisplayMessageFormatActionMenu::changeDisplayMessageFormat, this, &KMMainWidget::slotChangeDisplayMessageFormat);
3068 actionCollection()->addAction(QStringLiteral("display_format_message"), mDisplayMessageFormatMenu);
3070 mPreferHtmlLoadExtAction = new KToggleAction(i18n("Load E&xternal References"), this);
3071 actionCollection()->addAction(QStringLiteral("prefer_html_external_refs"), mPreferHtmlLoadExtAction);
3072 connect(mPreferHtmlLoadExtAction, &KToggleAction::triggered, this, &KMMainWidget::slotOverrideHtmlLoadExt);
3075 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyCollections);
3076 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::CTRL + Qt::Key_C));
3079 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::Paste);
3080 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::CTRL + Qt::Key_V));
3083 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyItems);
3084 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::CTRL + Qt::Key_C));
3087 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CutItems);
3088 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::CTRL + Qt::Key_X));
3092 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyItemToMenu);
3093 action->setText(i18n("Copy Message To..."));
3094 action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::MoveItemToMenu);
3095 action->setText(i18n("Move Message To..."));
3098 //----- Message Menu
3100 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("mail-message-new")), i18n("&New Message..."), this);
3101 actionCollection()->addAction(QStringLiteral("new_message"), action);
3102 action->setIconText(i18nc("@action:intoolbar New Empty Message", "New"));
3103 connect(action, &QAction::triggered, this, &KMMainWidget::slotCompose);
3104 // do not set a New shortcut if kmail is a component
3105 if (!kmkernel->xmlGuiInstanceName().isEmpty()) {
3106 actionCollection()->setDefaultShortcut(action, KStandardShortcut::openNew().first());
3110 mTemplateMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("document-new")), i18n("Message From &Template"),
3111 actionCollection());
3112 mTemplateMenu->setDelayed(true);
3113 actionCollection()->addAction(QStringLiteral("new_from_template"), mTemplateMenu);
3114 connect(mTemplateMenu->menu(), &QMenu::aboutToShow, this,
3115 &KMMainWidget::slotShowNewFromTemplate);
3116 connect(mTemplateMenu->menu(), &QMenu::triggered, this,
3117 &KMMainWidget::slotNewFromTemplate);
3119 mMessageNewList = new QAction(QIcon::fromTheme(QStringLiteral("mail-message-new-list")),
3120 i18n("New Message t&o Mailing-List..."),
3121 this);
3122 actionCollection()->addAction(QStringLiteral("post_message"), mMessageNewList);
3123 connect(mMessageNewList, &QAction::triggered,
3124 this, &KMMainWidget::slotPostToML);
3125 actionCollection()->setDefaultShortcut(mMessageNewList, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_N));
3127 mSendAgainAction = new QAction(i18n("Send A&gain..."), this);
3128 actionCollection()->addAction(QStringLiteral("send_again"), mSendAgainAction);
3129 connect(mSendAgainAction, &QAction::triggered, this, &KMMainWidget::slotResendMsg);
3131 //----- Create filter actions
3132 mFilterMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("&Create Filter"), this);
3133 actionCollection()->addAction(QStringLiteral("create_filter"), mFilterMenu);
3134 connect(mFilterMenu, &QAction::triggered, this,
3135 &KMMainWidget::slotFilter);
3137 QAction *action = new QAction(i18n("Filter on &Subject..."), this);
3138 actionCollection()->addAction(QStringLiteral("subject_filter"), action);
3139 connect(action, &QAction::triggered, this, &KMMainWidget::slotSubjectFilter);
3140 mFilterMenu->addAction(action);
3144 QAction *action = new QAction(i18n("Filter on &From..."), this);
3145 actionCollection()->addAction(QStringLiteral("from_filter"), action);
3146 connect(action, &QAction::triggered, this, &KMMainWidget::slotFromFilter);
3147 mFilterMenu->addAction(action);
3150 QAction *action = new QAction(i18n("Filter on &To..."), this);
3151 actionCollection()->addAction(QStringLiteral("to_filter"), action);
3152 connect(action, &QAction::triggered, this, &KMMainWidget::slotToFilter);
3153 mFilterMenu->addAction(action);
3156 QAction *action = new QAction(i18n("Filter on &Cc..."), this);
3157 actionCollection()->addAction(QStringLiteral("cc_filter"), action);
3158 connect(action, &QAction::triggered, this, &KMMainWidget::slotCcFilter);
3159 mFilterMenu->addAction(action);
3161 mFilterMenu->addAction(mMsgActions->listFilterAction());
3163 mUseAction = new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("New Message From &Template"), this);
3164 actionCollection()->addAction(QStringLiteral("use_template"), mUseAction);
3165 connect(mUseAction, &QAction::triggered, this, &KMMainWidget::slotUseTemplate);
3166 actionCollection()->setDefaultShortcut(mUseAction, QKeySequence(Qt::SHIFT + Qt::Key_N));
3168 //----- "Mark Thread" submenu
3169 mThreadStatusMenu = new KActionMenu(i18n("Mark &Thread"), this);
3170 actionCollection()->addAction(QStringLiteral("thread_status"), mThreadStatusMenu);
3172 mMarkThreadAsReadAction = new QAction(QIcon::fromTheme(QStringLiteral("mail-mark-read")), i18n("Mark Thread as &Read"), this);
3173 actionCollection()->addAction(QStringLiteral("thread_read"), mMarkThreadAsReadAction);
3174 connect(mMarkThreadAsReadAction, &QAction::triggered, this, &KMMainWidget::slotSetThreadStatusRead);
3175 KMail::Util::addQActionHelpText(mMarkThreadAsReadAction, i18n("Mark all messages in the selected thread as read"));
3176 mThreadStatusMenu->addAction(mMarkThreadAsReadAction);
3178 mMarkThreadAsUnreadAction = new QAction(QIcon::fromTheme(QStringLiteral("mail-mark-unread")), i18n("Mark Thread as &Unread"), this);
3179 actionCollection()->addAction(QStringLiteral("thread_unread"), mMarkThreadAsUnreadAction);
3180 connect(mMarkThreadAsUnreadAction, &QAction::triggered, this, &KMMainWidget::slotSetThreadStatusUnread);
3181 KMail::Util::addQActionHelpText(mMarkThreadAsUnreadAction, i18n("Mark all messages in the selected thread as unread"));
3182 mThreadStatusMenu->addAction(mMarkThreadAsUnreadAction);
3184 mThreadStatusMenu->addSeparator();
3186 //----- "Mark Thread" toggle actions
3187 mToggleThreadImportantAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-mark-important")), i18n("Mark Thread as &Important"), this);
3188 actionCollection()->addAction(QStringLiteral("thread_flag"), mToggleThreadImportantAction);
3189 connect(mToggleThreadImportantAction, &KToggleAction::triggered, this, &KMMainWidget::slotSetThreadStatusImportant);
3190 mToggleThreadImportantAction->setCheckedState(KGuiItem(i18n("Remove &Important Thread Mark")));
3191 mThreadStatusMenu->addAction(mToggleThreadImportantAction);
3193 mToggleThreadToActAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-mark-task")), i18n("Mark Thread as &Action Item"), this);
3194 actionCollection()->addAction(QStringLiteral("thread_toact"), mToggleThreadToActAction);
3195 connect(mToggleThreadToActAction, &KToggleAction::triggered, this, &KMMainWidget::slotSetThreadStatusToAct);
3196 mToggleThreadToActAction->setCheckedState(KGuiItem(i18n("Remove &Action Item Thread Mark")));
3197 mThreadStatusMenu->addAction(mToggleThreadToActAction);
3199 //------- "Watch and ignore thread" actions
3200 mWatchThreadAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-thread-watch")), i18n("&Watch Thread"), this);
3201 actionCollection()->addAction(QStringLiteral("thread_watched"), mWatchThreadAction);
3202 connect(mWatchThreadAction, &KToggleAction::triggered, this, &KMMainWidget::slotSetThreadStatusWatched);
3204 mIgnoreThreadAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-thread-ignored")), i18n("&Ignore Thread"), this);
3205 actionCollection()->addAction(QStringLiteral("thread_ignored"), mIgnoreThreadAction);
3206 connect(mIgnoreThreadAction, &KToggleAction::triggered, this, &KMMainWidget::slotSetThreadStatusIgnored);
3208 mThreadStatusMenu->addSeparator();
3209 mThreadStatusMenu->addAction(mWatchThreadAction);
3210 mThreadStatusMenu->addAction(mIgnoreThreadAction);
3212 mSaveAttachmentsAction = new QAction(QIcon::fromTheme(QStringLiteral("mail-attachment")), i18n("Save A&ttachments..."), this);
3213 actionCollection()->addAction(QStringLiteral("file_save_attachments"), mSaveAttachmentsAction);
3214 connect(mSaveAttachmentsAction, &QAction::triggered, this, &KMMainWidget::slotSaveAttachments);
3216 mMoveActionMenu = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::MoveItemToMenu);
3218 mCopyActionMenu = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyItemToMenu);
3220 mApplyAllFiltersAction =
3221 new QAction(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("Appl&y All Filters"), this);
3222 actionCollection()->addAction(QStringLiteral("apply_filters"), mApplyAllFiltersAction);
3223 connect(mApplyAllFiltersAction, &QAction::triggered,
3224 this, &KMMainWidget::slotApplyFilters);
3225 actionCollection()->setDefaultShortcut(mApplyAllFiltersAction, QKeySequence(Qt::CTRL + Qt::Key_J));
3227 mApplyFilterActionsMenu = new KActionMenu(i18n("A&pply Filter"), this);
3228 actionCollection()->addAction(QStringLiteral("apply_filter_actions"), mApplyFilterActionsMenu);
3231 QAction *action = new QAction(i18nc("View->", "&Expand Thread / Group"), this);
3232 actionCollection()->addAction(QStringLiteral("expand_thread"), action);
3233 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Period));
3234 KMail::Util::addQActionHelpText(action, i18n("Expand the current thread or group"));
3235 connect(action, &QAction::triggered, this, &KMMainWidget::slotExpandThread);
3238 QAction *action = new QAction(i18nc("View->", "&Collapse Thread / Group"), this);
3239 actionCollection()->addAction(QStringLiteral("collapse_thread"), action);
3240 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Comma));
3241 KMail::Util::addQActionHelpText(action, i18n("Collapse the current thread or group"));
3242 connect(action, &QAction::triggered, this, &KMMainWidget::slotCollapseThread);
3245 QAction *action = new QAction(i18nc("View->", "Ex&pand All Threads"), this);
3246 actionCollection()->addAction(QStringLiteral("expand_all_threads"), action);
3247 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Period));
3248 KMail::Util::addQActionHelpText(action, i18n("Expand all threads in the current folder"));
3249 connect(action, &QAction::triggered, this, &KMMainWidget::slotExpandAllThreads);
3252 QAction *action = new QAction(i18nc("View->", "C&ollapse All Threads"), this);
3253 actionCollection()->addAction(QStringLiteral("collapse_all_threads"), action);
3254 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Comma));
3255 KMail::Util::addQActionHelpText(action, i18n("Collapse all threads in the current folder"));
3256 connect(action, &QAction::triggered, this, &KMMainWidget::slotCollapseAllThreads);
3259 QAction *dukeOfMonmoth = new QAction(i18n("&Display Message"), this);
3260 actionCollection()->addAction(QStringLiteral("display_message"), dukeOfMonmoth);
3261 connect(dukeOfMonmoth, &QAction::triggered, this, &KMMainWidget::slotDisplayCurrentMessage);
3262 QList<QKeySequence> shortcuts;
3263 shortcuts << QKeySequence(Qt::Key_Enter) << QKeySequence(Qt::Key_Return);
3264 actionCollection()->setDefaultShortcuts(dukeOfMonmoth, shortcuts);
3266 //----- Go Menu
3268 QAction *action = new QAction(i18n("&Next Message"), this);
3269 actionCollection()->addAction(QStringLiteral("go_next_message"), action);
3270 actionCollection()->setDefaultShortcut(action, QKeySequence(QStringLiteral("N; Right")));
3271 KMail::Util::addQActionHelpText(action, i18n("Go to the next message"));
3272 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectNextMessage);
3275 QAction *action = new QAction(i18n("Next &Unread Message"), this);
3276 actionCollection()->addAction(QStringLiteral("go_next_unread_message"), action);
3277 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(Qt::Key_Plus) << QKeySequence(Qt::Key_Plus + Qt::KeypadModifier));
3278 if (QApplication::isRightToLeft()) {
3279 action->setIcon(QIcon::fromTheme(QStringLiteral("go-previous")));
3280 } else {
3281 action->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
3283 action->setIconText(i18nc("@action:inmenu Goto next unread message", "Next"));
3284 KMail::Util::addQActionHelpText(action, i18n("Go to the next unread message"));
3285 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectNextUnreadMessage);
3288 QAction *action = new QAction(i18n("&Previous Message"), this);
3289 actionCollection()->addAction(QStringLiteral("go_prev_message"), action);
3290 KMail::Util::addQActionHelpText(action, i18n("Go to the previous message"));
3291 actionCollection()->setDefaultShortcut(action, QKeySequence(QStringLiteral("P; Left")));
3292 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectPreviousMessage);
3295 QAction *action = new QAction(i18n("Previous Unread &Message"), this);
3296 actionCollection()->addAction(QStringLiteral("go_prev_unread_message"), action);
3297 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(Qt::Key_Minus) << QKeySequence(Qt::Key_Minus + Qt::KeypadModifier));
3298 if (QApplication::isRightToLeft()) {
3299 action->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
3300 } else {
3301 action->setIcon(QIcon::fromTheme(QStringLiteral("go-previous")));
3303 action->setIconText(i18nc("@action:inmenu Goto previous unread message.", "Previous"));
3304 KMail::Util::addQActionHelpText(action, i18n("Go to the previous unread message"));
3305 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectPreviousUnreadMessage);
3308 QAction *action = new QAction(i18n("Next Unread &Folder"), this);
3309 actionCollection()->addAction(QStringLiteral("go_next_unread_folder"), action);
3310 connect(action, &QAction::triggered, this, &KMMainWidget::slotNextUnreadFolder);
3311 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Plus) << QKeySequence(Qt::ALT + Qt::Key_Plus + Qt::KeypadModifier));
3312 KMail::Util::addQActionHelpText(action, i18n("Go to the next folder with unread messages"));
3315 QAction *action = new QAction(i18n("Previous Unread F&older"), this);
3316 actionCollection()->addAction(QStringLiteral("go_prev_unread_folder"), action);
3317 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Minus) << QKeySequence(Qt::ALT + Qt::Key_Minus + Qt::KeypadModifier));
3318 KMail::Util::addQActionHelpText(action, i18n("Go to the previous folder with unread messages"));
3319 connect(action, &QAction::triggered, this, &KMMainWidget::slotPrevUnreadFolder);
3322 QAction *action = new QAction(i18nc("Go->", "Next Unread &Text"), this);
3323 actionCollection()->addAction(QStringLiteral("go_next_unread_text"), action);
3324 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Space));
3325 KMail::Util::addQActionHelpText(action, i18n("Go to the next unread text"));
3326 action->setWhatsThis(i18n("Scroll down current message. "
3327 "If at end of current message, "
3328 "go to next unread message."));
3329 connect(action, &QAction::triggered, this, &KMMainWidget::slotReadOn);
3332 //----- Settings Menu
3334 QAction *action = new QAction(i18n("Configure &Filters..."), this);
3335 action->setMenuRole(QAction::NoRole); // do not move to application menu on OS X
3336 actionCollection()->addAction(QStringLiteral("filter"), action);
3337 connect(action, &QAction::triggered, this, &KMMainWidget::slotFilter);
3340 QAction *action = new QAction(i18n("Manage &Sieve Scripts..."), this);
3341 actionCollection()->addAction(QStringLiteral("sieveFilters"), action);
3342 connect(action, &QAction::triggered, this, &KMMainWidget::slotManageSieveScripts);
3345 mShowIntroductionAction = new QAction(QIcon::fromTheme(QStringLiteral("kmail")), i18n("KMail &Introduction"), this);
3346 actionCollection()->addAction(QStringLiteral("help_kmail_welcomepage"), mShowIntroductionAction);
3347 KMail::Util::addQActionHelpText(mShowIntroductionAction, i18n("Display KMail's Welcome Page"));
3348 connect(mShowIntroductionAction, &QAction::triggered, this, &KMMainWidget::slotIntro);
3349 mShowIntroductionAction->setEnabled(mMsgView != Q_NULLPTR);
3352 // ----- Standard Actions
3354 // KStandardAction::configureNotifications(this, SLOT(slotEditNotifications()), actionCollection());
3356 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("preferences-desktop-notification")),
3357 i18n("Configure &Notifications..."), this);
3358 action->setMenuRole(QAction::NoRole); // do not move to application menu on OS X
3359 actionCollection()->addAction(QStringLiteral("kmail_configure_notifications"), action);
3360 connect(action, &QAction::triggered, this, &KMMainWidget::slotEditNotifications);
3364 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("&Configure KMail..."), this);
3365 action->setMenuRole(QAction::PreferencesRole); // this one should move to the application menu on OS X
3366 actionCollection()->addAction(QStringLiteral("kmail_configure_kmail"), action);
3367 connect(action, &QAction::triggered, kmkernel, &KMKernel::slotShowConfigurationDialog);
3371 mExpireConfigAction = new QAction(i18n("Expire..."), this);
3372 actionCollection()->addAction(QStringLiteral("expire_settings"), mExpireConfigAction);
3373 connect(mExpireConfigAction, &QAction::triggered, mManageShowCollectionProperties, &ManageShowCollectionProperties::slotShowExpiryProperties);
3377 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("bookmark-new")), i18n("Add Favorite Folder..."), this);
3378 actionCollection()->addAction(QStringLiteral("add_favorite_folder"), action);
3379 connect(action, &QAction::triggered, this, &KMMainWidget::slotAddFavoriteFolder);
3383 mServerSideSubscription = new QAction(QIcon::fromTheme(QStringLiteral("folder-bookmarks")), i18n("Serverside Subscription..."), this);
3384 actionCollection()->addAction(QStringLiteral("serverside_subscription"), mServerSideSubscription);
3385 connect(mServerSideSubscription, &QAction::triggered, this, &KMMainWidget::slotServerSideSubscription);
3389 mApplyFiltersOnFolder = new QAction(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("Appl&y All Filters On Folder"), this);
3390 actionCollection()->addAction(QStringLiteral("apply_filters_on_folder"), mApplyFiltersOnFolder);
3391 connect(mApplyFiltersOnFolder, &QAction::triggered,
3392 this, &KMMainWidget::slotApplyFiltersOnFolder);
3397 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("kmail")), i18n("&Export KMail Data..."), this);
3398 actionCollection()->addAction(QStringLiteral("kmail_export_data"), action);
3399 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotExportData);
3403 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("contact-new")), i18n("New AddressBook Contact..."), this);
3404 actionCollection()->addAction(QStringLiteral("kmail_new_addressbook_contact"), action);
3405 connect(action, &QAction::triggered, this, &KMMainWidget::slotCreateAddressBookContact);
3409 actionCollection()->addAction(KStandardAction::Undo, QStringLiteral("kmail_undo"), this, SLOT(slotUndo()));
3411 menutimer = new QTimer(this);
3412 menutimer->setObjectName(QStringLiteral("menutimer"));
3413 menutimer->setSingleShot(true);
3414 connect(menutimer, &QTimer::timeout, this, &KMMainWidget::updateMessageActionsDelayed);
3415 connect(kmkernel->undoStack(),
3416 &KMail::UndoStack::undoStackChanged, this, &KMMainWidget::slotUpdateUndo);
3418 updateMessageActions();
3419 updateFolderMenu();
3420 mTagActionManager = new KMail::TagActionManager(this, actionCollection(), mMsgActions,
3421 mGUIClient);
3422 mFolderShortcutActionManager = new KMail::FolderShortcutActionManager(this, actionCollection());
3425 QAction *action = new QAction(i18n("Copy Message to Folder"), this);
3426 actionCollection()->addAction(QStringLiteral("copy_message_to_folder"), action);
3427 connect(action, &QAction::triggered,
3428 this, &KMMainWidget::slotCopySelectedMessagesToFolder);
3429 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_C));
3432 QAction *action = new QAction(i18n("Jump to Folder..."), this);
3433 actionCollection()->addAction(QStringLiteral("jump_to_folder"), action);
3434 connect(action, &QAction::triggered,
3435 this, &KMMainWidget::slotJumpToFolder);
3436 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_J));
3439 QAction *action = new QAction(i18n("Abort Current Operation"), this);
3440 actionCollection()->addAction(QStringLiteral("cancel"), action);
3441 connect(action, &QAction::triggered,
3442 ProgressManager::instance(), &KPIM::ProgressManager::slotAbortAll);
3443 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Escape));
3446 QAction *action = new QAction(i18n("Focus on Next Folder"), this);
3447 actionCollection()->addAction(QStringLiteral("inc_current_folder"), action);
3448 connect(action, &QAction::triggered,
3449 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotFocusNextFolder);
3450 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Right));
3453 QAction *action = new QAction(i18n("Focus on Previous Folder"), this);
3454 actionCollection()->addAction(QStringLiteral("dec_current_folder"), action);
3455 connect(action, &QAction::triggered,
3456 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotFocusPrevFolder);
3457 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Left));
3460 QAction *action = new QAction(i18n("Select Folder with Focus"), this);
3461 actionCollection()->addAction(QStringLiteral("select_current_folder"), action);
3463 connect(action, &QAction::triggered,
3464 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotSelectFocusFolder);
3465 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Space));
3468 QAction *action = new QAction(i18n("Focus on First Folder"), this);
3469 actionCollection()->addAction(QStringLiteral("focus_first_folder"), action);
3470 connect(action, &QAction::triggered,
3471 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotFocusFirstFolder);
3472 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Home));
3475 QAction *action = new QAction(i18n("Focus on Last Folder"), this);
3476 actionCollection()->addAction(QStringLiteral("focus_last_folder"), action);
3477 connect(action, &QAction::triggered,
3478 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotFocusLastFolder);
3479 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_End));
3482 QAction *action = new QAction(i18n("Focus on Next Message"), this);
3483 actionCollection()->addAction(QStringLiteral("inc_current_message"), action);
3484 connect(action, &QAction::triggered,
3485 this, &KMMainWidget::slotFocusOnNextMessage);
3486 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Right));
3489 QAction *action = new QAction(i18n("Focus on Previous Message"), this);
3490 actionCollection()->addAction(QStringLiteral("dec_current_message"), action);
3491 connect(action, &QAction::triggered,
3492 this, &KMMainWidget::slotFocusOnPrevMessage);
3493 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Left));
3496 QAction *action = new QAction(i18n("Select First Message"), this);
3497 actionCollection()->addAction(QStringLiteral("select_first_message"), action);
3498 connect(action, &QAction::triggered,
3499 this, &KMMainWidget::slotSelectFirstMessage);
3500 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Home));
3503 QAction *action = new QAction(i18n("Select Last Message"), this);
3504 actionCollection()->addAction(QStringLiteral("select_last_message"), action);
3505 connect(action, &QAction::triggered,
3506 this, &KMMainWidget::slotSelectLastMessage);
3507 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_End));
3510 QAction *action = new QAction(i18n("Select Message with Focus"), this);
3511 actionCollection()->addAction(QStringLiteral("select_current_message"), action);
3512 connect(action, &QAction::triggered,
3513 this, &KMMainWidget::slotSelectFocusedMessage);
3514 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Space));
3518 mQuickSearchAction = new QAction(i18n("Set Focus to Quick Search"), this);
3519 //If change shortcut change Panel::setQuickSearchClickMessage(...) message
3520 actionCollection()->setDefaultShortcut(mQuickSearchAction, QKeySequence(Qt::ALT + Qt::Key_Q));
3521 actionCollection()->addAction(QStringLiteral("focus_to_quickseach"), mQuickSearchAction);
3522 connect(mQuickSearchAction, &QAction::triggered,
3523 this, &KMMainWidget::slotFocusQuickSearch);
3524 updateQuickSearchLineText();
3527 QAction *action = new QAction(i18n("Extend Selection to Previous Message"), this);
3528 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::Key_Left));
3529 actionCollection()->addAction(QStringLiteral("previous_message"), action);
3530 connect(action, &QAction::triggered,
3531 this, &KMMainWidget::slotExtendSelectionToPreviousMessage);
3534 QAction *action = new QAction(i18n("Extend Selection to Next Message"), this);
3535 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::Key_Right));
3536 actionCollection()->addAction(QStringLiteral("next_message"), action);
3537 connect(action, &QAction::triggered,
3538 this, &KMMainWidget::slotExtendSelectionToNextMessage);
3542 mMoveMsgToFolderAction = new QAction(i18n("Move Message to Folder"), this);
3543 actionCollection()->setDefaultShortcut(mMoveMsgToFolderAction, QKeySequence(Qt::Key_M));
3544 actionCollection()->addAction(QStringLiteral("move_message_to_folder"), mMoveMsgToFolderAction);
3545 connect(mMoveMsgToFolderAction, &QAction::triggered,
3546 this, &KMMainWidget::slotMoveSelectedMessageToFolder);
3549 mArchiveAction = new QAction(i18nc("@action", "Archive"), this);
3550 actionCollection()->addAction(QStringLiteral("archive_mails"), mArchiveAction);
3551 connect(mArchiveAction, &QAction::triggered, this, &KMMainWidget::slotArchiveMails);
3553 mLowBandwithAction = new KToggleAction(i18n("Low Bandwidth"), this);
3554 actionCollection()->addAction(QStringLiteral("low_bandwidth"), mLowBandwithAction);
3555 connect(mLowBandwithAction, &KToggleAction::triggered, this, &KMMainWidget::slotBandwidth);
3559 void KMMainWidget::slotAddFavoriteFolder()
3561 if (!mFavoritesModel) {
3562 return;
3564 QPointer<MailCommon::FolderSelectionDialog> dialog(selectFromAllFoldersDialog());
3565 dialog->setWindowTitle(i18n("Add Favorite Folder"));
3566 if (dialog->exec() && dialog) {
3567 const Akonadi::Collection collection = dialog->selectedCollection();
3568 if (collection.isValid()) {
3569 mFavoritesModel->addCollection(collection);
3574 //-----------------------------------------------------------------------------
3575 void KMMainWidget::slotEditNotifications()
3577 KMail::KMKnotify notifyDlg(this);
3578 notifyDlg.exec();
3581 //-----------------------------------------------------------------------------
3582 void KMMainWidget::slotReadOn()
3584 if (!mMsgView) {
3585 return;
3587 if (!mMsgView->viewer()->atBottom()) {
3588 mMsgView->viewer()->slotJumpDown();
3589 return;
3591 slotSelectNextUnreadMessage();
3594 void KMMainWidget::slotNextUnreadFolder()
3596 if (!mFolderTreeWidget) {
3597 return;
3599 mGoToFirstUnreadMessageInSelectedFolder = true;
3600 mFolderTreeWidget->folderTreeView()->selectNextUnreadFolder();
3601 mGoToFirstUnreadMessageInSelectedFolder = false;
3604 void KMMainWidget::slotPrevUnreadFolder()
3606 if (!mFolderTreeWidget) {
3607 return;
3609 mGoToFirstUnreadMessageInSelectedFolder = true;
3610 mFolderTreeWidget->folderTreeView()->selectPrevUnreadFolder();
3611 mGoToFirstUnreadMessageInSelectedFolder = false;
3614 void KMMainWidget::slotExpandThread()
3616 mMessagePane->setCurrentThreadExpanded(true);
3619 void KMMainWidget::slotCollapseThread()
3621 mMessagePane->setCurrentThreadExpanded(false);
3624 void KMMainWidget::slotExpandAllThreads()
3626 // TODO: Make this asynchronous ? (if there is enough demand)
3627 #ifndef QT_NO_CURSOR
3628 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
3629 #endif
3630 mMessagePane->setAllThreadsExpanded(true);
3633 void KMMainWidget::slotCollapseAllThreads()
3635 // TODO: Make this asynchronous ? (if there is enough demand)
3636 #ifndef QT_NO_CURSOR
3637 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
3638 #endif
3639 mMessagePane->setAllThreadsExpanded(false);
3642 //-----------------------------------------------------------------------------
3643 void KMMainWidget::updateMessageMenu()
3645 updateMessageActions();
3648 void KMMainWidget::startUpdateMessageActionsTimer()
3650 // FIXME: This delay effectively CAN make the actions to be in an incoherent state
3651 // Maybe we should mark actions as "dirty" here and check it in every action handler...
3652 updateMessageActions(true);
3654 menutimer->stop();
3655 menutimer->start(500);
3658 void KMMainWidget::updateMessageActions(bool fast)
3660 Akonadi::Item::List selectedItems;
3661 Akonadi::Item::List selectedVisibleItems;
3662 bool allSelectedBelongToSameThread = false;
3663 if (mCurrentFolder && mCurrentFolder->isValid() &&
3664 mMessagePane->getSelectionStats(selectedItems, selectedVisibleItems, &allSelectedBelongToSameThread)
3666 mMsgActions->setCurrentMessage(mMessagePane->currentItem(), selectedVisibleItems);
3667 } else {
3668 mMsgActions->setCurrentMessage(Akonadi::Item());
3671 if (!fast) {
3672 updateMessageActionsDelayed();
3677 void KMMainWidget::updateMessageActionsDelayed()
3679 int count;
3680 Akonadi::Item::List selectedItems;
3681 Akonadi::Item::List selectedVisibleItems;
3682 bool allSelectedBelongToSameThread = false;
3683 Akonadi::Item currentMessage;
3684 if (mCurrentFolder && mCurrentFolder->isValid() &&
3685 mMessagePane->getSelectionStats(selectedItems, selectedVisibleItems, &allSelectedBelongToSameThread)
3687 count = selectedItems.count();
3689 currentMessage = mMessagePane->currentItem();
3691 } else {
3692 count = 0;
3693 currentMessage = Akonadi::Item();
3696 mApplyFiltersOnFolder->setEnabled(mCurrentFolder && mCurrentFolder->isValid());
3699 // Here we have:
3701 // - A list of selected messages stored in selectedSernums.
3702 // The selected messages might contain some invisible ones as a selected
3703 // collapsed node "includes" all the children in the selection.
3704 // - A list of selected AND visible messages stored in selectedVisibleSernums.
3705 // This list does not contain children of selected and collapsed nodes.
3707 // Now, actions can operate on:
3708 // - Any set of messages
3709 // These are called "mass actions" and are enabled whenever we have a message selected.
3710 // In fact we should differentiate between actions that operate on visible selection
3711 // and those that operate on the selection as a whole (without considering visibility)...
3712 // - A single thread
3713 // These are called "thread actions" and are enabled whenever all the selected messages belong
3714 // to the same thread. If the selection doesn't cover the whole thread then the action
3715 // will act on the whole thread anyway (thus will silently extend the selection)
3716 // - A single message
3717 // And we have two sub-cases:
3718 // - The selection must contain exactly one message
3719 // These actions can't ignore the hidden messages and thus must be disabled if
3720 // the selection contains any.
3721 // - The selection must contain exactly one visible message
3722 // These actions will ignore the hidden message and thus can be enabled if
3723 // the selection contains any.
3726 bool readOnly = mCurrentFolder && mCurrentFolder->isValid() && (mCurrentFolder->rights() & Akonadi::Collection::ReadOnly);
3727 // can we apply strictly single message actions ? (this is false if the whole selection contains more than one message)
3728 bool single_actions = count == 1;
3729 // can we apply loosely single message actions ? (this is false if the VISIBLE selection contains more than one message)
3730 bool singleVisibleMessageSelected = selectedVisibleItems.count() == 1;
3731 // can we apply "mass" actions to the selection ? (this is actually always true if the selection is non-empty)
3732 bool mass_actions = count >= 1;
3733 // does the selection identify a single thread ?
3734 bool thread_actions = mass_actions && allSelectedBelongToSameThread && mMessagePane->isThreaded();
3735 // can we apply flags to the selected messages ?
3736 bool flags_available = KMailSettings::self()->allowLocalFlags() || !(mCurrentFolder && mCurrentFolder->isValid() ? readOnly : true);
3738 mThreadStatusMenu->setEnabled(thread_actions);
3739 // these need to be handled individually, the user might have them
3740 // in the toolbar
3741 mWatchThreadAction->setEnabled(thread_actions && flags_available);
3742 mIgnoreThreadAction->setEnabled(thread_actions && flags_available);
3743 mMarkThreadAsReadAction->setEnabled(thread_actions);
3744 mMarkThreadAsUnreadAction->setEnabled(thread_actions);
3745 mToggleThreadToActAction->setEnabled(thread_actions && flags_available);
3746 mToggleThreadImportantAction->setEnabled(thread_actions && flags_available);
3747 bool canDeleteMessages = mCurrentFolder && mCurrentFolder->isValid() && (mCurrentFolder->rights() & Akonadi::Collection::CanDeleteItem);
3749 mTrashThreadAction->setEnabled(thread_actions && canDeleteMessages);
3750 mDeleteThreadAction->setEnabled(thread_actions && canDeleteMessages);
3752 if (currentMessage.isValid()) {
3753 MessageStatus status;
3754 status.setStatusFromFlags(currentMessage.flags());
3755 mTagActionManager->updateActionStates(count, mMessagePane->currentItem());
3756 if (thread_actions) {
3757 mToggleThreadToActAction->setChecked(status.isToAct());
3758 mToggleThreadImportantAction->setChecked(status.isImportant());
3759 mWatchThreadAction->setChecked(status.isWatched());
3760 mIgnoreThreadAction->setChecked(status.isIgnored());
3764 mMoveActionMenu->setEnabled(mass_actions && canDeleteMessages);
3765 if (mMoveMsgToFolderAction) {
3766 mMoveMsgToFolderAction->setEnabled(mass_actions && canDeleteMessages);
3768 //mCopyActionMenu->setEnabled( mass_actions );
3770 mDeleteAction->setEnabled(mass_actions && canDeleteMessages);
3772 mExpireConfigAction->setEnabled(canDeleteMessages);
3774 if (mMsgView) {
3775 mMsgView->findInMessageAction()->setEnabled(mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3777 mMsgActions->forwardInlineAction()->setEnabled(mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3778 mMsgActions->forwardAttachedAction()->setEnabled(mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3779 mMsgActions->forwardMenu()->setEnabled(mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3781 mMsgActions->editAction()->setEnabled(single_actions);
3782 mUseAction->setEnabled(single_actions && CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3783 filterMenu()->setEnabled(single_actions);
3784 mMsgActions->redirectAction()->setEnabled(/*single_actions &&*/mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3786 if (mMsgActions->customTemplatesMenu()) {
3787 mMsgActions->customTemplatesMenu()->forwardActionMenu()->setEnabled(mass_actions);
3788 mMsgActions->customTemplatesMenu()->replyActionMenu()->setEnabled(single_actions);
3789 mMsgActions->customTemplatesMenu()->replyAllActionMenu()->setEnabled(single_actions);
3792 // "Print" will act on the current message: it will ignore any hidden selection
3793 mMsgActions->printAction()->setEnabled(singleVisibleMessageSelected);
3794 // "Print preview" will act on the current message: it will ignore any hidden selection
3795 QAction *printPreviewAction = mMsgActions->printPreviewAction();
3796 if (printPreviewAction) {
3797 printPreviewAction->setEnabled(singleVisibleMessageSelected);
3800 // "View Source" will act on the current message: it will ignore any hidden selection
3801 if (mMsgView) {
3802 mMsgView->viewSourceAction()->setEnabled(singleVisibleMessageSelected);
3804 MessageStatus status;
3805 status.setStatusFromFlags(currentMessage.flags());
3807 QList< QAction *> actionList;
3808 bool statusSendAgain = single_actions && ((currentMessage.isValid() && status.isSent()) || (currentMessage.isValid() && CommonKernel->folderIsSentMailFolder(mCurrentFolder->collection())));
3809 if (statusSendAgain) {
3810 actionList << mSendAgainAction;
3811 } else if (single_actions) {
3812 actionList << messageActions()->editAction();
3814 actionList << mSaveAttachmentsAction;
3815 if (mCurrentFolder && FolderArchive::FolderArchiveUtil::resourceSupportArchiving(mCurrentFolder->collection().resource())) {
3816 actionList << mArchiveAction;
3818 mGUIClient->unplugActionList(QStringLiteral("messagelist_actionlist"));
3819 mGUIClient->plugActionList(QStringLiteral("messagelist_actionlist"), actionList);
3820 mSendAgainAction->setEnabled(statusSendAgain);
3822 mSaveAsAction->setEnabled(mass_actions);
3824 if ((mCurrentFolder && mCurrentFolder->isValid())) {
3825 updateMoveAction(mCurrentFolder->statistics());
3826 } else {
3827 updateMoveAction(false, false);
3830 const qint64 nbMsgOutboxCollection = MailCommon::Util::updatedCollection(CommonKernel->outboxCollectionFolder()).statistics().count();
3832 mSendQueued->setEnabled(nbMsgOutboxCollection > 0);
3833 mSendActionMenu->setEnabled(nbMsgOutboxCollection > 0);
3835 const bool newPostToMailingList = mCurrentFolder && mCurrentFolder->isMailingListEnabled();
3836 mMessageNewList->setEnabled(newPostToMailingList);
3838 slotUpdateOnlineStatus(static_cast<GlobalSettingsBase::EnumNetworkState::type>(KMailSettings::self()->networkState()));
3839 if (action(QStringLiteral("kmail_undo"))) {
3840 action(QStringLiteral("kmail_undo"))->setEnabled(kmkernel->undoStack()->size() > 0);
3843 // Enable / disable all filters.
3844 foreach (QAction *filterAction, mFilterMenuActions) {
3845 filterAction->setEnabled(count > 0);
3848 mApplyAllFiltersAction->setEnabled(count);
3849 mApplyFilterActionsMenu->setEnabled(count);
3852 void KMMainWidget::slotAkonadiStandardActionUpdated()
3854 bool multiFolder = false;
3855 if (mFolderTreeWidget) {
3856 multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3858 if (mCollectionProperties) {
3859 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
3860 const Akonadi::AgentInstance instance =
3861 Akonadi::AgentManager::self()->instance(mCurrentFolder->collection().resource());
3863 mCollectionProperties->setEnabled(!multiFolder &&
3864 !mCurrentFolder->isStructural() &&
3865 (instance.status() != Akonadi::AgentInstance::Broken));
3866 } else {
3867 mCollectionProperties->setEnabled(false);
3869 QList< QAction * > collectionProperties;
3870 if (mCollectionProperties->isEnabled()) {
3871 collectionProperties << mCollectionProperties;
3873 mGUIClient->unplugActionList(QStringLiteral("akonadi_collection_collectionproperties_actionlist"));
3874 mGUIClient->plugActionList(QStringLiteral("akonadi_collection_collectionproperties_actionlist"), collectionProperties);
3878 const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural();
3880 if (mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::DeleteCollections)) {
3882 mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::DeleteCollections)->setEnabled(mCurrentFolder
3883 && !multiFolder
3884 && (mCurrentFolder->collection().rights() & Collection::CanDeleteCollection)
3885 && !mCurrentFolder->isSystemFolder()
3886 && folderWithContent);
3889 if (mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)) {
3890 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)->setEnabled(folderWithContent
3891 && (mCurrentFolder->count() > 0)
3892 && mCurrentFolder->canDeleteMessages()
3893 && !multiFolder);
3894 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)->setText((mCurrentFolder && CommonKernel->folderIsTrash(mCurrentFolder->collection())) ? i18n("E&mpty Trash") : i18n("&Move All Messages to Trash"));
3897 QList< QAction * > addToFavorite;
3898 QAction *actionAddToFavoriteCollections = akonadiStandardAction(Akonadi::StandardActionManager::AddToFavoriteCollections);
3899 if (actionAddToFavoriteCollections) {
3900 if (mEnableFavoriteFolderView && actionAddToFavoriteCollections->isEnabled()) {
3901 addToFavorite << actionAddToFavoriteCollections;
3903 mGUIClient->unplugActionList(QStringLiteral("akonadi_collection_add_to_favorites_actionlist"));
3904 mGUIClient->plugActionList(QStringLiteral("akonadi_collection_add_to_favorites_actionlist"), addToFavorite);
3907 QList< QAction * > syncActionList;
3908 QAction *actionSync = akonadiStandardAction(Akonadi::StandardActionManager::SynchronizeCollections);
3909 if (actionSync && actionSync->isEnabled()) {
3910 syncActionList << actionSync;
3912 actionSync = akonadiStandardAction(Akonadi::StandardActionManager::SynchronizeCollectionsRecursive);
3913 if (actionSync && actionSync->isEnabled()) {
3914 syncActionList << actionSync;
3916 mGUIClient->unplugActionList(QStringLiteral("akonadi_collection_sync_actionlist"));
3917 mGUIClient->plugActionList(QStringLiteral("akonadi_collection_sync_actionlist"), syncActionList);
3919 QList< QAction * > actionList;
3921 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CreateCollection);
3922 if (action && action->isEnabled()) {
3923 actionList << action;
3926 action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::MoveCollectionToMenu);
3927 if (action && action->isEnabled()) {
3928 actionList << action;
3931 action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyCollectionToMenu);
3932 if (action && action->isEnabled()) {
3933 actionList << action;
3935 mGUIClient->unplugActionList(QStringLiteral("akonadi_collection_move_copy_menu_actionlist"));
3936 mGUIClient->plugActionList(QStringLiteral("akonadi_collection_move_copy_menu_actionlist"), actionList);
3940 void KMMainWidget::updateHtmlMenuEntry()
3942 if (mDisplayMessageFormatMenu && mPreferHtmlLoadExtAction) {
3943 bool multiFolder = false;
3944 if (mFolderTreeWidget) {
3945 multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3947 // the visual ones only make sense if we are showing a message list
3948 const bool enabledAction = (mFolderTreeWidget &&
3949 mFolderTreeWidget->folderTreeView()->currentFolder().isValid() &&
3950 !multiFolder);
3952 mDisplayMessageFormatMenu->setEnabled(enabledAction);
3953 const bool isEnabled = (mFolderTreeWidget &&
3954 mFolderTreeWidget->folderTreeView()->currentFolder().isValid() &&
3955 !multiFolder);
3956 const bool useHtml = (mFolderDisplayFormatPreference == MessageViewer::Viewer::Html || (mHtmlGlobalSetting && mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting));
3957 mPreferHtmlLoadExtAction->setEnabled(isEnabled && useHtml);
3959 mDisplayMessageFormatMenu->setDisplayMessageFormat(mFolderDisplayFormatPreference);
3961 mPreferHtmlLoadExtAction->setChecked(!multiFolder && (mHtmlLoadExtGlobalSetting ? !mFolderHtmlLoadExtPreference : mFolderHtmlLoadExtPreference));
3965 //-----------------------------------------------------------------------------
3966 void KMMainWidget::updateFolderMenu()
3968 if (!CommonKernel->outboxCollectionFolder().isValid()) {
3969 QTimer::singleShot(1000, this, &KMMainWidget::updateFolderMenu);
3970 return;
3973 const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural();
3974 bool multiFolder = false;
3975 if (mFolderTreeWidget) {
3976 multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3978 mFolderMailingListPropertiesAction->setEnabled(folderWithContent &&
3979 !multiFolder &&
3980 !mCurrentFolder->isSystemFolder());
3982 QList< QAction * > actionlist;
3983 if (mCurrentFolder && mCurrentFolder->collection().id() == CommonKernel->outboxCollectionFolder().id() && (mCurrentFolder->collection()).statistics().count() > 0) {
3984 qCDebug(KMAIL_LOG) << "Enabling send queued";
3985 mSendQueued->setEnabled(true);
3986 actionlist << mSendQueued;
3988 // if ( mCurrentFolder && mCurrentFolder->collection().id() != CommonKernel->trashCollectionFolder().id() ) {
3989 // actionlist << mTrashAction;
3990 // }
3991 mGUIClient->unplugActionList(QStringLiteral("outbox_folder_actionlist"));
3992 mGUIClient->plugActionList(QStringLiteral("outbox_folder_actionlist"), actionlist);
3993 actionlist.clear();
3995 const bool isASearchFolder = mCurrentFolder && mCurrentFolder->collection().resource() == QLatin1String("akonadi_search_resource");
3996 if (isASearchFolder) {
3997 mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::DeleteCollections)->setText(i18n("&Delete Search"));
4000 mArchiveFolderAction->setEnabled(mCurrentFolder && !multiFolder && folderWithContent);
4002 bool isInTrashFolder = (mCurrentFolder && CommonKernel->folderIsTrash(mCurrentFolder->collection()));
4003 QAction *moveToTrash = akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash);
4004 akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash)->setText(isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "&Delete") : i18n("&Move to Trash"));
4005 akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash)->setIcon(isInTrashFolder ? QIcon::fromTheme(QStringLiteral("edit-delete")) : QIcon::fromTheme(QStringLiteral("user-trash")));
4006 //Use same text as in Text property. Change it in kf5
4007 moveToTrash->setToolTip(isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "&Delete") : i18n("&Move to Trash"));
4009 mTrashThreadAction->setIcon(isInTrashFolder ? QIcon::fromTheme(QStringLiteral("edit-delete")) : QIcon::fromTheme(QStringLiteral("user-trash")));
4010 mTrashThreadAction->setText(isInTrashFolder ? i18n("Delete T&hread") : i18n("M&ove Thread to Trash"));
4012 mSearchMessages->setText((mCurrentFolder && mCurrentFolder->collection().resource() == QLatin1String("akonadi_search_resource")) ? i18n("Edit Search...") : i18n("&Find Messages..."));
4014 mExpireConfigAction->setEnabled(mCurrentFolder &&
4015 !mCurrentFolder->isStructural() &&
4016 !multiFolder &&
4017 mCurrentFolder->canDeleteMessages() &&
4018 folderWithContent &&
4019 !MailCommon::Util::isVirtualCollection(mCurrentFolder->collection()));
4021 updateHtmlMenuEntry();
4023 mShowFolderShortcutDialogAction->setEnabled(!multiFolder && folderWithContent);
4025 actionlist << akonadiStandardAction(Akonadi::StandardActionManager::ManageLocalSubscriptions);
4026 bool imapFolderIsOnline = false;
4027 if (mCurrentFolder && PimCommon::Util::isImapFolder(mCurrentFolder->collection(), imapFolderIsOnline)) {
4028 if (imapFolderIsOnline) {
4029 actionlist << mServerSideSubscription;
4033 mGUIClient->unplugActionList(QStringLiteral("collectionview_actionlist"));
4034 mGUIClient->plugActionList(QStringLiteral("collectionview_actionlist"), actionlist);
4038 //-----------------------------------------------------------------------------
4039 void KMMainWidget::slotIntro()
4041 if (!mMsgView) {
4042 return;
4045 mMsgView->clear(true);
4047 // hide widgets that are in the way:
4048 if (mMessagePane && mLongFolderList) {
4049 mMessagePane->hide();
4051 mMsgView->displayAboutPage();
4053 mCurrentFolder.clear();
4056 void KMMainWidget::slotShowStartupFolder()
4058 connect(MailCommon::FilterManager::instance(), &FilterManager::filtersChanged,
4059 this, &KMMainWidget::initializeFilterActions);
4060 // Plug various action lists. This can't be done in the constructor, as that is called before
4061 // the main window or Kontact calls createGUI().
4062 // This function however is called with a single shot timer.
4063 checkAkonadiServerManagerState();
4064 mFolderShortcutActionManager->createActions();
4065 mTagActionManager->createActions();
4066 messageActions()->setupForwardingActionsList(mGUIClient);
4068 QString newFeaturesMD5 = KMReaderWin::newFeaturesMD5();
4069 if (kmkernel->firstStart() ||
4070 KMailSettings::self()->previousNewFeaturesMD5() != newFeaturesMD5) {
4071 KMailSettings::self()->setPreviousNewFeaturesMD5(newFeaturesMD5);
4072 slotIntro();
4073 return;
4077 void KMMainWidget::checkAkonadiServerManagerState()
4079 Akonadi::ServerManager::State state = Akonadi::ServerManager::self()->state();
4080 if (state == Akonadi::ServerManager::Running) {
4081 initializeFilterActions();
4082 } else {
4083 connect(Akonadi::ServerManager::self(), &ServerManager::stateChanged,
4084 this, &KMMainWidget::slotServerStateChanged);
4088 void KMMainWidget::slotServerStateChanged(Akonadi::ServerManager::State state)
4090 if (state == Akonadi::ServerManager::Running) {
4091 initializeFilterActions();
4092 disconnect(Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)));
4096 QList<KActionCollection *> KMMainWidget::actionCollections() const
4098 return QList<KActionCollection *>() << actionCollection();
4101 //-----------------------------------------------------------------------------
4102 void KMMainWidget::slotUpdateUndo()
4104 if (actionCollection()->action(QStringLiteral("kmail_undo"))) {
4105 QAction *act = actionCollection()->action(QStringLiteral("kmail_undo"));
4106 act->setEnabled(!kmkernel->undoStack()->isEmpty());
4107 const QString infoStr = kmkernel->undoStack()->undoInfo();
4108 if (infoStr.isEmpty()) {
4109 act->setText(i18n("&Undo"));
4110 } else {
4111 act->setText(i18n("&Undo: \"%1\"", kmkernel->undoStack()->undoInfo()));
4116 //-----------------------------------------------------------------------------
4117 void KMMainWidget::clearFilterActions()
4119 if (!mFilterTBarActions.isEmpty())
4120 if (mGUIClient->factory()) {
4121 mGUIClient->unplugActionList(QStringLiteral("toolbar_filter_actions"));
4124 if (!mFilterMenuActions.isEmpty())
4125 if (mGUIClient->factory()) {
4126 mGUIClient->unplugActionList(QStringLiteral("menu_filter_actions"));
4129 foreach (QAction *a, mFilterMenuActions) {
4130 actionCollection()->removeAction(a);
4133 mApplyFilterActionsMenu->menu()->clear();
4134 mFilterTBarActions.clear();
4135 mFilterMenuActions.clear();
4137 qDeleteAll(mFilterCommands);
4138 mFilterCommands.clear();
4141 //-----------------------------------------------------------------------------
4142 void KMMainWidget::initializeFilterActions()
4144 clearFilterActions();
4145 mApplyFilterActionsMenu->menu()->addAction(mApplyAllFiltersAction);
4146 bool addedSeparator = false;
4148 foreach (MailFilter *filter, MailCommon::FilterManager::instance()->filters()) {
4149 if (!filter->isEmpty() && filter->configureShortcut() && filter->isEnabled()) {
4150 QString filterName = QStringLiteral("Filter %1").arg(filter->name());
4151 QString normalizedName = filterName.replace(QLatin1Char(' '), QLatin1Char('_'));
4152 if (action(normalizedName)) {
4153 continue;
4155 KMMetaFilterActionCommand *filterCommand = new KMMetaFilterActionCommand(filter->identifier(), this);
4156 mFilterCommands.append(filterCommand);
4157 QString displayText = i18n("Filter %1", filter->name());
4158 QString icon = filter->icon();
4159 if (icon.isEmpty()) {
4160 icon = QStringLiteral("system-run");
4162 QAction *filterAction = new QAction(QIcon::fromTheme(icon), displayText, actionCollection());
4163 filterAction->setIconText(filter->toolbarName());
4165 // The shortcut configuration is done in the filter dialog.
4166 // The shortcut set in the shortcut dialog would not be saved back to
4167 // the filter settings correctly.
4168 actionCollection()->setShortcutsConfigurable(filterAction, false);
4169 actionCollection()->addAction(normalizedName,
4170 filterAction);
4171 connect(filterAction, &QAction::triggered,
4172 filterCommand, &KMMetaFilterActionCommand::start);
4173 actionCollection()->setDefaultShortcut(filterAction, filter->shortcut());
4174 if (!addedSeparator) {
4175 QAction *a = mApplyFilterActionsMenu->menu()->addSeparator();
4176 mFilterMenuActions.append(a);
4177 addedSeparator = true;
4179 mApplyFilterActionsMenu->menu()->addAction(filterAction);
4180 mFilterMenuActions.append(filterAction);
4181 if (filter->configureToolbar()) {
4182 mFilterTBarActions.append(filterAction);
4186 if (!mFilterMenuActions.isEmpty() && mGUIClient->factory()) {
4187 mGUIClient->plugActionList(QStringLiteral("menu_filter_actions"), mFilterMenuActions);
4189 if (!mFilterTBarActions.isEmpty() && mGUIClient->factory()) {
4190 mFilterTBarActions.prepend(mToolbarActionSeparator);
4191 mGUIClient->plugActionList(QStringLiteral("toolbar_filter_actions"), mFilterTBarActions);
4194 // Our filters have changed, now enable/disable them
4195 updateMessageActions();
4198 void KMMainWidget::updateFileMenu()
4200 const bool isEmpty = MailCommon::Util::agentInstances().isEmpty();
4201 actionCollection()->action(QStringLiteral("check_mail"))->setEnabled(!isEmpty);
4202 actionCollection()->action(QStringLiteral("check_mail_in"))->setEnabled(!isEmpty);
4205 //-----------------------------------------------------------------------------
4206 const KMMainWidget::PtrList *KMMainWidget::mainWidgetList()
4208 // better safe than sorry; check whether the global static has already been destroyed
4209 if (theMainWidgetList.isDestroyed()) {
4210 return Q_NULLPTR;
4212 return theMainWidgetList;
4215 QSharedPointer<FolderCollection> KMMainWidget::currentFolder() const
4217 return mCurrentFolder;
4220 //-----------------------------------------------------------------------------
4221 QString KMMainWidget::overrideEncoding() const
4223 if (mMsgView) {
4224 return mMsgView->overrideEncoding();
4225 } else {
4226 return MessageCore::MessageCoreSettings::self()->overrideCharacterEncoding();
4230 void KMMainWidget::showEvent(QShowEvent *event)
4232 QWidget::showEvent(event);
4233 mWasEverShown = true;
4236 void KMMainWidget::slotRequestFullSearchFromQuickSearch()
4238 // First, open the search window. If we are currently on a search folder,
4239 // the search associated with that will be loaded.
4240 if (!slotSearch()) {
4241 return;
4244 assert(mSearchWin);
4246 // Now we look at the current state of the quick search, and if there's
4247 // something in there, we add the criteria to the existing search for
4248 // the search folder, if applicable, or make a new one from it.
4249 SearchPattern pattern;
4250 const QString searchString = mMessagePane->currentFilterSearchString();
4251 if (!searchString.isEmpty()) {
4252 MessageList::Core::QuickSearchLine::SearchOptions options = mMessagePane->currentOptions();
4253 QByteArray searchStringVal;
4254 if (options & MessageList::Core::QuickSearchLine::SearchEveryWhere) {
4255 searchStringVal = "<message>";
4256 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstSubject) {
4257 searchStringVal = "subject";
4258 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstBody) {
4259 searchStringVal = "<body>";
4260 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstFrom) {
4261 searchStringVal = "from";
4262 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstBcc) {
4263 searchStringVal = "bcc";
4264 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstTo) {
4265 searchStringVal = "to";
4266 } else {
4267 searchStringVal = "<message>";
4269 pattern.append(SearchRule::createInstance(searchStringVal, SearchRule::FuncContains, searchString));
4270 QList<MessageStatus> statusList = mMessagePane->currentFilterStatus();
4271 Q_FOREACH (MessageStatus status, statusList) {
4272 if (status.hasAttachment()) {
4273 pattern.append(SearchRule::createInstance(searchStringVal, SearchRule::FuncHasAttachment, searchString));
4274 status.setHasAttachment(false);
4276 if (!status.isOfUnknownStatus()) {
4277 pattern.append(SearchRule::Ptr(new SearchRuleStatus(status)));
4281 if (!pattern.isEmpty()) {
4282 mSearchWin->addRulesToSearchPattern(pattern);
4286 void KMMainWidget::updateVacationScriptStatus(bool active, const QString &serverName)
4288 mVacationScriptIndicator->setVacationScriptActive(active, serverName);
4289 mVacationIndicatorActive = mVacationScriptIndicator->hasVacationScriptActive();
4292 QWidget *KMMainWidget::vacationScriptIndicator() const
4294 return mVacationScriptIndicator;
4297 void KMMainWidget::updateVacationScriptStatus()
4299 updateVacationScriptStatus(mVacationIndicatorActive);
4302 KMail::TagActionManager *KMMainWidget::tagActionManager() const
4304 return mTagActionManager;
4307 KMail::FolderShortcutActionManager *KMMainWidget::folderShortcutActionManager() const
4309 return mFolderShortcutActionManager;
4312 void KMMainWidget::slotMessageSelected(const Akonadi::Item &item)
4314 delete mShowBusySplashTimer;
4315 mShowBusySplashTimer = Q_NULLPTR;
4316 if (mMsgView) {
4317 // The current selection was cleared, so we'll remove the previously
4318 // selected message from the preview pane
4319 if (!item.isValid()) {
4320 mMsgView->clear();
4321 } else {
4322 mShowBusySplashTimer = new QTimer(this);
4323 mShowBusySplashTimer->setSingleShot(true);
4324 connect(mShowBusySplashTimer, &QTimer::timeout, this, &KMMainWidget::slotShowBusySplash);
4325 mShowBusySplashTimer->start(1000);
4327 Akonadi::ItemFetchJob *itemFetchJob = MessageViewer::Viewer::createFetchJob(item);
4328 if (mCurrentFolder) {
4329 const QString resource = mCurrentFolder->collection().resource();
4330 itemFetchJob->setProperty("_resource", QVariant::fromValue(resource));
4331 connect(itemFetchJob, &ItemFetchJob::itemsReceived,
4332 this, &KMMainWidget::itemsReceived);
4333 connect(itemFetchJob, &Akonadi::ItemFetchJob::result, this, &KMMainWidget::itemsFetchDone);
4339 void KMMainWidget::itemsReceived(const Akonadi::Item::List &list)
4341 Q_ASSERT(list.size() == 1);
4342 delete mShowBusySplashTimer;
4343 mShowBusySplashTimer = Q_NULLPTR;
4345 if (!mMsgView) {
4346 return;
4349 Item item = list.first();
4351 if (mMessagePane) {
4352 mMessagePane->show();
4354 if (mMessagePane->currentItem() != item) {
4355 // The user has selected another email already, so don't render this one.
4356 // Mark it as read, though, if the user settings say so.
4357 if (MessageViewer::MessageViewerSettings::self()->delayedMarkAsRead() &&
4358 MessageViewer::MessageViewerSettings::self()->delayedMarkTime() == 0) {
4359 item.setFlag(Akonadi::MessageFlags::Seen);
4360 Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob(item, this);
4361 modifyJob->disableRevisionCheck();
4362 modifyJob->setIgnorePayload(true);
4364 return;
4368 mMsgView->setMessage(item);
4369 // reset HTML Q_DECL_OVERRIDE to the folder setting
4370 mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
4371 mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
4372 mMsgView->setDecryptMessageOverwrite(false);
4373 mMsgActions->setCurrentMessage(item);
4376 void KMMainWidget::itemsFetchDone(KJob *job)
4378 delete mShowBusySplashTimer;
4379 mShowBusySplashTimer = Q_NULLPTR;
4380 if (job->error()) {
4381 // Unfortunately job->error() is Job::Unknown in many cases.
4382 // (see JobPrivate::handleResponse in akonadi/job.cpp)
4383 // So we show the "offline" page after checking the resource status.
4384 qCDebug(KMAIL_LOG) << job->error() << job->errorString();
4386 const QString resource = job->property("_resource").toString();
4387 const Akonadi::AgentInstance agentInstance = Akonadi::AgentManager::self()->instance(resource);
4388 if (!agentInstance.isOnline()) {
4389 // The resource is offline
4390 if (mMsgView) {
4391 mMsgView->viewer()->enableMessageDisplay();
4392 mMsgView->clear(true);
4394 mMessagePane->show();
4396 if (kmkernel->isOffline()) {
4397 showOfflinePage();
4398 } else {
4399 if (mMsgView) {
4400 showResourceOfflinePage();
4403 } else {
4404 // Some other error
4405 BroadcastStatus::instance()->setStatusMsg(job->errorString());
4410 QAction *KMMainWidget::akonadiStandardAction(Akonadi::StandardActionManager::Type type)
4412 return mAkonadiStandardActionManager->action(type);
4415 QAction *KMMainWidget::akonadiStandardAction(Akonadi::StandardMailActionManager::Type type)
4417 return mAkonadiStandardActionManager->action(type);
4420 void KMMainWidget::slotRemoveDuplicates()
4422 RemoveDuplicateMailJob *job = new RemoveDuplicateMailJob(mFolderTreeWidget->folderTreeView()->selectionModel(), this, this);
4423 job->start();
4426 void KMMainWidget::slotServerSideSubscription()
4428 if (!mCurrentFolder) {
4429 return;
4431 PimCommon::ManageServerSideSubscriptionJob *job = new PimCommon::ManageServerSideSubscriptionJob(this);
4432 job->setCurrentCollection(mCurrentFolder->collection());
4433 job->setParentWidget(this);
4434 job->start();
4437 void KMMainWidget::savePaneSelection()
4439 if (mMessagePane) {
4440 mMessagePane->saveCurrentSelection();
4444 void KMMainWidget::updatePaneTagComboBox()
4446 if (mMessagePane) {
4447 mMessagePane->updateTagComboBox();
4451 void KMMainWidget::slotCreateAddressBookContact()
4453 CreateNewContactJob *job = new CreateNewContactJob(this, this);
4454 job->start();
4457 void KMMainWidget::slotOpenRecentMsg(const QUrl &url)
4459 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand(this, url, overrideEncoding(), this);
4460 openCommand->start();
4463 void KMMainWidget::addRecentFile(const QUrl &mUrl)
4465 mOpenRecentAction->addUrl(mUrl);
4466 KConfigGroup grp = mConfig->group(QStringLiteral("Recent Files"));
4467 mOpenRecentAction->saveEntries(grp);
4468 grp.sync();
4471 void KMMainWidget::slotMoveMessageToTrash()
4473 if (messageView() && messageView()->viewer()) {
4474 KMTrashMsgCommand *command = new KMTrashMsgCommand(mCurrentFolder->collection(), messageView()->viewer()->messageItem(), -1);
4475 command->start();
4479 void KMMainWidget::slotArchiveMails()
4481 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
4482 KMKernel::self()->folderArchiveManager()->setArchiveItems(selectedMessages, mCurrentFolder->collection().resource());
4485 void KMMainWidget::updateQuickSearchLineText()
4487 //If change change shortcut
4488 mMessagePane->setQuickSearchClickMessage(i18nc("Show shortcut for focus quick search. Don't change it", "Search...<%1>", mQuickSearchAction->shortcut().toString()));
4491 void KMMainWidget::slotChangeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage format)
4493 if (format == MessageViewer::Viewer::Html) {
4494 const int result = KMessageBox::warningContinueCancel(this,
4495 // the warning text is taken from configuredialog.cpp:
4496 i18n("Use of HTML in mail will make you more vulnerable to "
4497 "\"spam\" and may increase the likelihood that your system will be "
4498 "compromised by other present and anticipated security exploits."),
4499 i18n("Security Warning"),
4500 KGuiItem(i18n("Use HTML")),
4501 KStandardGuiItem::cancel(),
4502 QStringLiteral("OverrideHtmlWarning"), Q_NULLPTR);
4503 if (result == KMessageBox::Cancel) {
4504 mDisplayMessageFormatMenu->setDisplayMessageFormat(MessageViewer::Viewer::Text);
4505 return;
4508 mFolderDisplayFormatPreference = format;
4510 //Update mPrefererHtmlLoadExtAction
4511 const bool useHtml = (mFolderDisplayFormatPreference == MessageViewer::Viewer::Html || (mHtmlGlobalSetting && mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting));
4512 mPreferHtmlLoadExtAction->setEnabled(useHtml);
4514 if (mMsgView) {
4515 mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
4516 mMsgView->update(true);
4520 void KMMainWidget::populateMessageListStatusFilterCombo()
4522 mMessagePane->populateStatusFilterCombo();
4525 void KMMainWidget::slotCollectionRemoved(const Akonadi::Collection &col)
4527 if (mFavoritesModel) {
4528 mFavoritesModel->removeCollection(col);