Clazy fix++
[kdepim.git] / kmail / kmmainwidget.cpp
blob5b3921212d58710670bdb819e7a914872fbf5513
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 #include "job/markallmessagesasreadinfolderandsubfolderjob.h"
51 #if !defined(NDEBUG)
52 #include <ksieveui/sievedebugdialog.h>
53 using KSieveUi::SieveDebugDialog;
54 #endif
56 #include "collectionpage/collectionmaintenancepage.h"
57 #include "collectionpage/collectionquotapage.h"
58 #include "collectionpage/collectiontemplatespage.h"
59 #include "collectionpage/collectionshortcutpage.h"
60 #include "collectionpage/collectionviewpage.h"
61 #include "collectionpage/collectionmailinglistpage.h"
62 #include "tag/tagselectdialog.h"
63 #include "job/createnewcontactjob.h"
64 #include "folderarchive/folderarchiveutil.h"
65 #include "folderarchive/folderarchivemanager.h"
67 #include "PimCommon/CollectionAclPage"
68 #include "PimCommon/PimUtil"
69 #include "MailCommon/CollectionGeneralPage"
70 #include "MailCommon/CollectionExpiryPage"
71 #include "MailCommon/ExpireCollectionAttribute"
72 #include "MailCommon/FilterManager"
73 #include "MailCommon/MailFilter"
74 #include "MailCommon/FavoriteCollectionWidget"
75 #include "MailCommon/FolderTreeWidget"
76 #include "MailCommon/FolderTreeView"
77 #include "mailcommonsettings_base.h"
78 #include "kmmainwidget.h"
80 // Other PIM includes
81 #include "kdepim-version.h"
83 #include "messageviewer/messageviewersettings.h"
84 #include "messageviewer/viewer.h"
85 #include "messageviewer/attachmentstrategy.h"
86 #ifndef QT_NO_CURSOR
87 #include "Libkdepim/KCursorSaver"
88 #endif
90 #include "MessageComposer/MessageSender"
91 #include "MessageComposer/MessageHelper"
93 #include "TemplateParser/TemplateParser"
95 #include "MessageCore/MessageCoreSettings"
96 #include "MessageCore/MailingList"
97 #include "messagecore/messagehelpers.h"
99 #include "dialog/kmknotify.h"
100 #include "widgets/displaymessageformatactionmenu.h"
102 #include "ksieveui/vacationmanager.h"
103 #include "kmlaunchexternalcomponent.h"
105 // LIBKDEPIM includes
106 #include "libkdepim/progressmanager.h"
107 #include "libkdepim/broadcaststatus.h"
109 // KDEPIMLIBS includes
110 #include <AkonadiCore/AgentManager>
111 #include <AkonadiCore/AttributeFactory>
112 #include <AkonadiCore/itemfetchjob.h>
113 #include <AkonadiCore/collectionattributessynchronizationjob.h>
114 #include <AkonadiCore/collectionfetchjob.h>
115 #include <AkonadiCore/collectionfetchscope.h>
116 #include <Akonadi/Contact/ContactSearchJob>
117 #include <AkonadiWidgets/collectionpropertiesdialog.h>
118 #include <AkonadiCore/entitydisplayattribute.h>
119 #include <AkonadiWidgets/entitylistview.h>
120 #include <AkonadiWidgets/etmviewstatesaver.h>
121 #include <AkonadiCore/agentinstance.h>
122 #include <AkonadiCore/agenttype.h>
123 #include <AkonadiCore/changerecorder.h>
124 #include <AkonadiCore/session.h>
125 #include <AkonadiCore/entitytreemodel.h>
126 #include <AkonadiCore/favoritecollectionsmodel.h>
127 #include <AkonadiCore/itemfetchscope.h>
128 #include <AkonadiCore/itemmodifyjob.h>
129 #include <AkonadiWidgets/controlgui.h>
130 #include <AkonadiWidgets/collectiondialog.h>
131 #include <AkonadiCore/collectionstatistics.h>
132 #include <AkonadiCore/EntityMimeTypeFilterModel>
133 #include <Akonadi/KMime/MessageFlags>
134 #include <Akonadi/KMime/RemoveDuplicatesJob>
135 #include <AkonadiCore/CachePolicy>
137 #include <kidentitymanagement/identity.h>
138 #include <kidentitymanagement/identitymanager.h>
139 #include <KEmailAddress>
140 #include <mailtransport/transportmanager.h>
141 #include <mailtransport/transport.h>
142 #include <kmime/kmime_mdn.h>
143 #include <kmime/kmime_header_parsing.h>
144 #include <kmime/kmime_message.h>
145 #include <ksieveui/managesievescriptsdialog.h>
146 #include <ksieveui/util.h>
148 // KDELIBS includes
149 #include <kwindowsystem.h>
150 #include <kmessagebox.h>
151 #include <kactionmenu.h>
152 #include <QMenu>
153 #include <kacceleratormanager.h>
154 #include <kstandardshortcut.h>
155 #include <kcharsets.h>
156 #include "kmail_debug.h"
157 #include <ktip.h>
159 #include <kstandardaction.h>
160 #include <ktoggleaction.h>
161 #include <knotification.h>
162 #include <knotifyconfigwidget.h>
163 #include <kstringhandler.h>
164 #include <kconfiggroup.h>
165 #include <ktoolinvocation.h>
166 #include <kxmlguifactory.h>
167 #include <kxmlguiclient.h>
168 #include <QStatusBar>
169 #include <QAction>
170 #include <ktreewidgetsearchline.h>
171 #include <KRecentFilesAction>
173 // Qt includes
174 #include <QByteArray>
175 #include <QHeaderView>
176 #include <QList>
177 #include <QSplitter>
178 #include <QVBoxLayout>
179 #include <QShortcut>
180 #include <QProcess>
181 #include <QDBusConnection>
182 #include <QTextDocument>
183 #include <QDir>
184 // System includes
185 #include <AkonadiWidgets/standardactionmanager.h>
186 #include <KHelpClient>
187 #include <QStandardPaths>
189 #include "PimCommon/ManageServerSideSubscriptionJob"
190 #include <job/removeduplicatemailjob.h>
191 #include <job/removecollectionjob.h>
193 using namespace KMime;
194 using namespace Akonadi;
195 using namespace MailCommon;
196 using KPIM::ProgressManager;
197 using KPIM::BroadcastStatus;
198 using KMail::SearchWindow;
199 using KMail::AntiSpamWizard;
200 using KMime::Types::AddrSpecList;
201 using MessageViewer::AttachmentStrategy;
203 Q_GLOBAL_STATIC(KMMainWidget::PtrList, theMainWidgetList)
205 //-----------------------------------------------------------------------------
206 KMMainWidget::KMMainWidget(QWidget *parent, KXMLGUIClient *aGUIClient,
207 KActionCollection *actionCollection, KSharedConfig::Ptr config) :
208 QWidget(parent),
209 mMoveMsgToFolderAction(Q_NULLPTR),
210 mCollectionProperties(Q_NULLPTR),
211 mFavoriteCollectionsView(Q_NULLPTR),
212 mMsgView(Q_NULLPTR),
213 mSplitter1(Q_NULLPTR),
214 mSplitter2(Q_NULLPTR),
215 mFolderViewSplitter(Q_NULLPTR),
216 mArchiveFolderAction(Q_NULLPTR),
217 mShowBusySplashTimer(Q_NULLPTR),
218 mMsgActions(Q_NULLPTR),
219 mCurrentFolder(Q_NULLPTR),
220 mVacationIndicatorActive(false),
221 mGoToFirstUnreadMessageInSelectedFolder(false),
222 mDisplayMessageFormatMenu(Q_NULLPTR),
223 mFolderDisplayFormatPreference(MessageViewer::Viewer::UseGlobalSetting),
224 mSearchMessages(Q_NULLPTR),
225 mManageShowCollectionProperties(new ManageShowCollectionProperties(this, this)),
226 mShowIntroductionAction(Q_NULLPTR),
227 mMarkAllMessageAsReadAndInAllSubFolder(Q_NULLPTR),
228 mAccountActionMenu(Q_NULLPTR)
230 mLaunchExternalComponent = new KMLaunchExternalComponent(this, this);
231 // must be the first line of the constructor:
232 mStartupDone = false;
233 mWasEverShown = false;
234 mReaderWindowActive = true;
235 mReaderWindowBelow = true;
236 mFolderHtmlLoadExtPreference = false;
237 mDestructed = false;
238 mActionCollection = actionCollection;
239 mTopLayout = new QVBoxLayout(this);
240 mTopLayout->setMargin(0);
241 mConfig = config;
242 mGUIClient = aGUIClient;
243 mFolderTreeWidget = Q_NULLPTR;
244 mPreferHtmlLoadExtAction = Q_NULLPTR;
245 Akonadi::ControlGui::widgetNeedsAkonadi(this);
246 mFavoritesModel = Q_NULLPTR;
247 mVacationManager = new KSieveUi::VacationManager(this);
249 mToolbarActionSeparator = new QAction(this);
250 mToolbarActionSeparator->setSeparator(true);
252 theMainWidgetList->append(this);
254 readPreConfig();
255 createWidgets();
256 setupActions();
258 readConfig();
260 if (!kmkernel->isOffline()) { //kmail is set to online mode, make sure the agents are also online
261 kmkernel->setAccountStatus(true);
264 QTimer::singleShot(0, this, &KMMainWidget::slotShowStartupFolder);
266 connect(kmkernel, &KMKernel::startCheckMail,
267 this, &KMMainWidget::slotStartCheckMail);
269 connect(kmkernel, &KMKernel::endCheckMail,
270 this, &KMMainWidget::slotEndCheckMail);
272 connect(kmkernel, &KMKernel::configChanged,
273 this, &KMMainWidget::slotConfigChanged);
275 connect(kmkernel, &KMKernel::onlineStatusChanged,
276 this, &KMMainWidget::slotUpdateOnlineStatus);
278 connect(mTagActionManager, &KMail::TagActionManager::tagActionTriggered,
279 this, &KMMainWidget::slotUpdateMessageTagList);
281 connect(mTagActionManager, &KMail::TagActionManager::tagMoreActionClicked,
282 this, &KMMainWidget::slotSelectMoreMessageTagList);
284 kmkernel->toggleSystemTray();
287 // make sure the pages are registered only once, since there can be multiple instances of KMMainWidget
288 static bool pagesRegistered = false;
290 if (!pagesRegistered) {
291 Akonadi::CollectionPropertiesDialog::registerPage(new PimCommon::CollectionAclPageFactory);
292 Akonadi::CollectionPropertiesDialog::registerPage(new MailCommon::CollectionGeneralPageFactory);
293 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionMaintenancePageFactory);
294 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionQuotaPageFactory);
295 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionTemplatesPageFactory);
296 Akonadi::CollectionPropertiesDialog::registerPage(new MailCommon::CollectionExpiryPageFactory);
297 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionViewPageFactory);
298 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionMailingListPageFactory);
299 Akonadi::CollectionPropertiesDialog::registerPage(new CollectionShortcutPageFactory);
301 pagesRegistered = true;
305 KMainWindow *mainWin = dynamic_cast<KMainWindow *>(window());
306 QStatusBar *sb = mainWin ? mainWin->statusBar() : Q_NULLPTR;
307 mVacationScriptIndicator = new KMail::VacationScriptIndicatorWidget(sb);
308 mVacationScriptIndicator->hide();
309 connect(mVacationScriptIndicator, &KMail::VacationScriptIndicatorWidget::clicked, this, &KMMainWidget::slotEditVacation);
310 if (KSieveUi::Util::checkOutOfOfficeOnStartup()) {
311 QTimer::singleShot(0, this, &KMMainWidget::slotCheckVacation);
314 connect(mFolderTreeWidget->folderTreeView()->model(), &QAbstractItemModel::modelReset,
315 this, &KMMainWidget::restoreCollectionFolderViewConfig);
316 restoreCollectionFolderViewConfig();
318 if (kmkernel->firstStart()) {
319 if (MailCommon::Util::foundMailer()) {
320 if (KMessageBox::questionYesNo(this, i18n("Another mailer was found on system. Do you want to import data from it?")) == KMessageBox::Yes) {
321 const QString path = QStandardPaths::findExecutable(QStringLiteral("importwizard"));
322 if (!QProcess::startDetached(path)) {
323 KMessageBox::error(this, i18n("Could not start the import wizard. "
324 "Please check your installation."),
325 i18n("Unable to start import wizard"));
327 } else {
328 mLaunchExternalComponent->slotAccountWizard();
330 } else {
331 mLaunchExternalComponent->slotAccountWizard();
334 // must be the last line of the constructor:
335 mStartupDone = true;
337 mCheckMailTimer.setInterval(3 * 1000);
338 mCheckMailTimer.setSingleShot(true);
339 connect(&mCheckMailTimer, &QTimer::timeout, this, &KMMainWidget::slotUpdateActionsAfterMailChecking);
343 void KMMainWidget::restoreCollectionFolderViewConfig()
345 ETMViewStateSaver *saver = new ETMViewStateSaver;
346 saver->setView(mFolderTreeWidget->folderTreeView());
347 const KConfigGroup cfg(KMKernel::self()->config(), "CollectionFolderView");
348 mFolderTreeWidget->restoreHeaderState(cfg.readEntry("HeaderState", QByteArray()));
349 saver->restoreState(cfg);
350 //Restore startup folder
352 Akonadi::Collection::Id id = -1;
353 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
354 id = mCurrentFolder->collection().id();
357 if (id == -1) {
358 if (KMailSettings::self()->startSpecificFolderAtStartup()) {
359 Akonadi::Collection::Id startupFolder = KMailSettings::self()->startupFolder();
360 if (startupFolder > 0) {
361 saver->restoreCurrentItem(QStringLiteral("c%1").arg(startupFolder));
364 } else {
365 saver->restoreCurrentItem(QStringLiteral("c%1").arg(id));
369 //-----------------------------------------------------------------------------
370 //The kernel may have already been deleted when this method is called,
371 //perform all cleanup that requires the kernel in destruct()
372 KMMainWidget::~KMMainWidget()
374 theMainWidgetList->removeAll(this);
375 qDeleteAll(mFilterCommands);
376 destruct();
379 //-----------------------------------------------------------------------------
380 //This method performs all cleanup that requires the kernel to exist.
381 void KMMainWidget::destruct()
383 if (mDestructed) {
384 return;
386 if (mSearchWin) {
387 mSearchWin->close();
389 writeConfig(false); /* don't force kmkernel sync when close BUG: 289287 */
390 writeFolderConfig();
391 deleteWidgets();
392 mCurrentFolder.clear();
393 delete mMoveOrCopyToDialog;
394 delete mSelectFromAllFoldersDialog;
396 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), this, Q_NULLPTR);
397 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)), this, Q_NULLPTR);
398 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), this, Q_NULLPTR);
399 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)), this, Q_NULLPTR);
400 disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), this, Q_NULLPTR);
402 mDestructed = true;
405 void KMMainWidget::slotStartCheckMail()
407 if (mCheckMailTimer.isActive()) {
408 mCheckMailTimer.stop();
412 void KMMainWidget::slotEndCheckMail()
414 if (!mCheckMailTimer.isActive()) {
415 mCheckMailTimer.start();
419 void KMMainWidget::slotUpdateActionsAfterMailChecking()
421 const bool sendOnAll =
422 KMailSettings::self()->sendOnCheck() == KMailSettings::EnumSendOnCheck::SendOnAllChecks;
423 const bool sendOnManual =
424 KMailSettings::self()->sendOnCheck() == KMailSettings::EnumSendOnCheck::SendOnManualChecks;
425 if (!kmkernel->isOffline() && (sendOnAll || sendOnManual)) {
426 slotSendQueued();
428 // update folder menus in case some mail got filtered to trash/current folder
429 // and we can enable "empty trash/move all to trash" action etc.
430 updateFolderMenu();
433 void KMMainWidget::slotCollectionFetched(int collectionId)
435 // Called when a collection is fetched for the first time by the ETM.
436 // This is the right time to update the caption (which still says "Loading...")
437 // and to update the actions that depend on the number of mails in the folder.
438 if (mCurrentFolder && collectionId == mCurrentFolder->collection().id()) {
439 mCurrentFolder->setCollection(MailCommon::Util::updatedCollection(mCurrentFolder->collection()));
440 updateMessageActions();
441 updateFolderMenu();
443 // We call this for any collection, it could be one of our parents...
444 if (mCurrentFolder) {
445 Q_EMIT captionChangeRequest(MailCommon::Util::fullCollectionPath(mCurrentFolder->collection()));
449 void KMMainWidget::slotFolderChanged(const Akonadi::Collection &collection)
451 folderSelected(collection);
452 if (collection.cachePolicy().syncOnDemand()) {
453 AgentManager::self()->synchronizeCollection(collection, false);
455 mMsgActions->setCurrentMessage(Akonadi::Item());
456 Q_EMIT captionChangeRequest(MailCommon::Util::fullCollectionPath(collection));
459 void KMMainWidget::folderSelected(const Akonadi::Collection &col)
461 // This is connected to the MainFolderView signal triggering when a folder is selected
463 if (mGoToFirstUnreadMessageInSelectedFolder) {
464 // the default action has been overridden from outside
465 mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered;
466 } else {
467 // use the default action
468 switch (KMailSettings::self()->actionEnterFolder()) {
469 case KMailSettings::EnumActionEnterFolder::SelectFirstUnread:
470 mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered;
471 break;
472 case KMailSettings::EnumActionEnterFolder::SelectLastSelected:
473 mPreSelectionMode = MessageList::Core::PreSelectLastSelected;
474 break;
475 case KMailSettings::EnumActionEnterFolder::SelectNewest:
476 mPreSelectionMode = MessageList::Core::PreSelectNewestCentered;
477 break;
478 case KMailSettings::EnumActionEnterFolder::SelectOldest:
479 mPreSelectionMode = MessageList::Core::PreSelectOldestCentered;
480 break;
481 default:
482 mPreSelectionMode = MessageList::Core::PreSelectNone;
483 break;
487 mGoToFirstUnreadMessageInSelectedFolder = false;
488 #ifndef QT_NO_CURSOR
489 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
490 #endif
492 if (mMsgView) {
493 mMsgView->clear(true);
495 const bool newFolder = mCurrentFolder && (mCurrentFolder->collection() != col);
497 // Delete any pending timer, if needed it will be recreated below
498 delete mShowBusySplashTimer;
499 mShowBusySplashTimer = Q_NULLPTR;
500 if (newFolder) {
501 // We're changing folder: write configuration for the old one
502 writeFolderConfig();
505 mCurrentFolder = FolderCollection::forCollection(col);
507 readFolderConfig();
508 if (mMsgView) {
509 mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
510 mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
513 if (!mCurrentFolder->isValid() && (mMessagePane->count() < 2)) {
514 slotIntro();
517 updateMessageActions();
518 updateFolderMenu();
520 // The message pane uses the selection model of the folder view to load the correct aggregation model and theme
521 // settings. At this point the selection model hasn't been updated yet to the user's new choice, so it would load
522 // the old folder settings instead.
523 QTimer::singleShot(0, this, &KMMainWidget::slotShowSelectedFolderInPane);
526 void KMMainWidget::slotShowSelectedFolderInPane()
528 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
529 mMessagePane->setCurrentFolder(mCurrentFolder->collection(), false, mPreSelectionMode);
533 void KMMainWidget::clearViewer()
535 if (mMsgView) {
536 mMsgView->clear(true);
537 mMsgView->displayAboutPage();
541 //-----------------------------------------------------------------------------
542 void KMMainWidget::readPreConfig()
544 mLongFolderList = KMailSettings::self()->folderList() == KMailSettings::EnumFolderList::longlist;
545 mReaderWindowActive = KMailSettings::self()->readerWindowMode() != KMailSettings::EnumReaderWindowMode::hide;
546 mReaderWindowBelow = KMailSettings::self()->readerWindowMode() == KMailSettings::EnumReaderWindowMode::below;
548 mHtmlGlobalSetting = MessageViewer::MessageViewerSettings::self()->htmlMail();
549 mHtmlLoadExtGlobalSetting = MessageViewer::MessageViewerSettings::self()->htmlLoadExternal();
551 mEnableFavoriteFolderView = (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() != MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode);
552 mEnableFolderQuickSearch = KMailSettings::self()->enableFolderQuickSearch();
553 readFolderConfig();
554 updateHtmlMenuEntry();
555 if (mMsgView) {
556 mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
557 mMsgView->update(true);
561 //-----------------------------------------------------------------------------
562 void KMMainWidget::readFolderConfig()
564 if (!mCurrentFolder || !mCurrentFolder->isValid()) {
565 return;
567 KSharedConfig::Ptr config = KMKernel::self()->config();
568 KConfigGroup group(config, MailCommon::FolderCollection::configGroupName(mCurrentFolder->collection()));
569 if (group.hasKey("htmlMailOverride")) {
570 const bool useHtml = group.readEntry("htmlMailOverride", false);
571 mFolderDisplayFormatPreference = useHtml ? MessageViewer::Viewer::Html : MessageViewer::Viewer::Text;
572 group.deleteEntry("htmlMailOverride");
573 group.sync();
574 } else {
575 mFolderDisplayFormatPreference = static_cast<MessageViewer::Viewer::DisplayFormatMessage>(group.readEntry("displayFormatOverride", static_cast<int>(MessageViewer::Viewer::UseGlobalSetting)));
577 mFolderHtmlLoadExtPreference =
578 group.readEntry("htmlLoadExternalOverride", false);
581 //-----------------------------------------------------------------------------
582 void KMMainWidget::writeFolderConfig()
584 if (mCurrentFolder && mCurrentFolder->isValid()) {
585 KSharedConfig::Ptr config = KMKernel::self()->config();
586 KConfigGroup group(config, MailCommon::FolderCollection::configGroupName(mCurrentFolder->collection()));
587 group.writeEntry("htmlLoadExternalOverride", mFolderHtmlLoadExtPreference);
588 if (mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting) {
589 group.deleteEntry("displayFormatOverride");
590 } else {
591 group.writeEntry("displayFormatOverride", static_cast<int>(mFolderDisplayFormatPreference));
596 //-----------------------------------------------------------------------------
597 void KMMainWidget::layoutSplitters()
599 // This function can only be called when the old splitters are already deleted
600 Q_ASSERT(!mSplitter1);
601 Q_ASSERT(!mSplitter2);
603 // For some reason, this is necessary here so that the copy action still
604 // works after changing the folder layout.
605 if (mMsgView)
606 disconnect(mMsgView->copyAction(), &QAction::triggered,
607 mMsgView, &KMReaderWin::slotCopySelectedText);
609 // If long folder list is enabled, the splitters are:
610 // Splitter 1: FolderView vs (HeaderAndSearch vs MessageViewer)
611 // Splitter 2: HeaderAndSearch vs MessageViewer
613 // If long folder list is disabled, the splitters are:
614 // Splitter 1: (FolderView vs HeaderAndSearch) vs MessageViewer
615 // Splitter 2: FolderView vs HeaderAndSearch
617 // The folder view is both the folder tree and the favorite folder view, if
618 // enabled
620 const bool readerWindowAtSide = !mReaderWindowBelow && mReaderWindowActive;
621 const bool readerWindowBelow = mReaderWindowBelow && mReaderWindowActive;
623 mSplitter1 = new QSplitter(this);
624 mSplitter2 = new QSplitter(mSplitter1);
626 QWidget *folderTreeWidget = mSearchAndTree;
627 if (mFavoriteCollectionsView) {
628 mFolderViewSplitter = new QSplitter(Qt::Vertical);
629 //mFolderViewSplitter->setChildrenCollapsible( false );
630 mFolderViewSplitter->addWidget(mFavoriteCollectionsView);
631 mFavoriteCollectionsView->setParent(mFolderViewSplitter);
632 mFolderViewSplitter->addWidget(mSearchAndTree);
633 folderTreeWidget = mFolderViewSplitter;
636 if (mLongFolderList) {
638 // add folder tree
639 mSplitter1->setOrientation(Qt::Horizontal);
640 mSplitter1->addWidget(folderTreeWidget);
642 // and the rest to the right
643 mSplitter1->addWidget(mSplitter2);
645 // add the message list to the right or below
646 if (readerWindowAtSide) {
647 mSplitter2->setOrientation(Qt::Horizontal);
648 } else {
649 mSplitter2->setOrientation(Qt::Vertical);
651 mSplitter2->addWidget(mMessagePane);
653 // add the preview window, if there is one
654 if (mMsgView) {
655 mSplitter2->addWidget(mMsgView);
658 } else { // short folder list
659 if (mReaderWindowBelow) {
660 mSplitter1->setOrientation(Qt::Vertical);
661 mSplitter2->setOrientation(Qt::Horizontal);
662 } else { // at side or none
663 mSplitter1->setOrientation(Qt::Horizontal);
664 mSplitter2->setOrientation(Qt::Vertical);
667 mSplitter1->addWidget(mSplitter2);
669 // add folder tree
670 mSplitter2->addWidget(folderTreeWidget);
671 // add message list to splitter 2
672 mSplitter2->addWidget(mMessagePane);
674 // add the preview window, if there is one
675 if (mMsgView) {
676 mSplitter1->addWidget(mMsgView);
681 // Set splitter properties
683 mSplitter1->setObjectName(QStringLiteral("splitter1"));
684 //mSplitter1->setChildrenCollapsible( false );
685 mSplitter2->setObjectName(QStringLiteral("splitter2"));
686 //mSplitter2->setChildrenCollapsible( false );
689 // Set the stretch factors
691 mSplitter1->setStretchFactor(0, 0);
692 mSplitter2->setStretchFactor(0, 0);
693 mSplitter1->setStretchFactor(1, 1);
694 mSplitter2->setStretchFactor(1, 1);
696 if (mFavoriteCollectionsView) {
697 mFolderViewSplitter->setStretchFactor(0, 0);
698 mFolderViewSplitter->setStretchFactor(1, 1);
701 // Because the reader windows's width increases a tiny bit after each
702 // restart in short folder list mode with message window at side, disable
703 // the stretching as a workaround here
704 if (readerWindowAtSide && !mLongFolderList) {
705 mSplitter1->setStretchFactor(0, 1);
706 mSplitter1->setStretchFactor(1, 0);
710 // Set the sizes of the splitters to the values stored in the config
712 QList<int> splitter1Sizes;
713 QList<int> splitter2Sizes;
715 const int folderViewWidth = KMailSettings::self()->folderViewWidth();
716 int ftHeight = KMailSettings::self()->folderTreeHeight();
717 int headerHeight = KMailSettings::self()->searchAndHeaderHeight();
718 const int messageViewerWidth = KMailSettings::self()->readerWindowWidth();
719 int headerWidth = KMailSettings::self()->searchAndHeaderWidth();
720 int messageViewerHeight = KMailSettings::self()->readerWindowHeight();
722 int ffvHeight = mFolderViewSplitter ? MailCommon::MailCommonSettings::self()->favoriteCollectionViewHeight() : 0;
724 // If the message viewer was hidden before, make sure it is not zero height
725 if (messageViewerHeight < 10 && readerWindowBelow) {
726 headerHeight /= 2;
727 messageViewerHeight = headerHeight;
730 if (mLongFolderList) {
731 if (!readerWindowAtSide) {
732 splitter1Sizes << folderViewWidth << headerWidth;
733 splitter2Sizes << headerHeight << messageViewerHeight;
734 } else {
735 splitter1Sizes << folderViewWidth << (headerWidth + messageViewerWidth);
736 splitter2Sizes << headerWidth << messageViewerWidth;
738 } else {
739 if (!readerWindowAtSide) {
740 splitter1Sizes << headerHeight << messageViewerHeight;
741 splitter2Sizes << folderViewWidth << headerWidth;
742 } else {
743 splitter1Sizes << headerWidth << messageViewerWidth;
744 splitter2Sizes << ftHeight + ffvHeight << messageViewerHeight;
748 mSplitter1->setSizes(splitter1Sizes);
749 mSplitter2->setSizes(splitter2Sizes);
751 if (mFolderViewSplitter) {
752 QList<int> splitterSizes;
753 splitterSizes << ffvHeight << ftHeight;
754 mFolderViewSplitter->setSizes(splitterSizes);
758 // Now add the splitters to the main layout
760 mTopLayout->addWidget(mSplitter1);
762 // Make sure the focus is on the view, and not on the quick search line edit, because otherwise
763 // shortcuts like + or j go to the wrong place.
764 // This would normally be done in the message list itself, but apparently something resets the focus
765 // again, probably all the reparenting we do here.
766 mMessagePane->focusView();
768 // By default hide th unread and size columns on first run.
769 if (kmkernel->firstStart()) {
770 mFolderTreeWidget->folderTreeView()->hideColumn(1);
771 mFolderTreeWidget->folderTreeView()->hideColumn(3);
772 mFolderTreeWidget->folderTreeView()->header()->resizeSection(0, folderViewWidth * 0.8);
775 // Make the copy action work, see disconnect comment above
776 if (mMsgView)
777 connect(mMsgView->copyAction(), &QAction::triggered,
778 mMsgView, &KMReaderWin::slotCopySelectedText);
781 //-----------------------------------------------------------------------------
782 void KMMainWidget::refreshFavoriteFoldersViewProperties()
784 if (mFavoriteCollectionsView) {
785 if (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode) {
786 mFavoriteCollectionsView->changeViewMode(QListView::IconMode);
787 } else if (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode) {
788 mFavoriteCollectionsView->changeViewMode(QListView::ListMode);
789 } else {
790 Q_ASSERT(false); // we should never get here in hidden mode
792 mFavoriteCollectionsView->setDropActionMenuEnabled(kmkernel->showPopupAfterDnD());
793 mFavoriteCollectionsView->setWordWrap(true);
794 mFavoriteCollectionsView->updateMode();
798 //-----------------------------------------------------------------------------
799 void KMMainWidget::readConfig()
801 const bool oldLongFolderList = mLongFolderList;
802 const bool oldReaderWindowActive = mReaderWindowActive;
803 const bool oldReaderWindowBelow = mReaderWindowBelow;
804 const bool oldFavoriteFolderView = mEnableFavoriteFolderView;
805 const bool oldFolderQuickSearch = mEnableFolderQuickSearch;
807 // on startup, the layout is always new and we need to relayout the widgets
808 bool layoutChanged = !mStartupDone;
810 if (mStartupDone) {
811 readPreConfig();
813 layoutChanged = (oldLongFolderList != mLongFolderList) ||
814 (oldReaderWindowActive != mReaderWindowActive) ||
815 (oldReaderWindowBelow != mReaderWindowBelow) ||
816 (oldFavoriteFolderView != mEnableFavoriteFolderView);
818 if (layoutChanged) {
819 deleteWidgets();
820 createWidgets();
821 restoreCollectionFolderViewConfig();
822 Q_EMIT recreateGui();
823 } else if (oldFolderQuickSearch != mEnableFolderQuickSearch) {
824 if (mEnableFolderQuickSearch) {
825 mFolderTreeWidget->filterFolderLineEdit()->show();
826 } else {
827 mFolderTreeWidget->filterFolderLineEdit()->hide();
833 // Read the config of the folder views and the header
834 if (mMsgView) {
835 mMsgView->readConfig();
837 mMessagePane->reloadGlobalConfiguration();
838 mFolderTreeWidget->readConfig();
839 if (mFavoriteCollectionsView) {
840 mFavoriteCollectionsView->readConfig();
842 refreshFavoriteFoldersViewProperties();
846 // area for config group "General"
847 if (!mStartupDone) {
848 // check mail on startup
849 // do it after building the kmmainwin, so that the progressdialog is available
850 QTimer::singleShot(0, this, &KMMainWidget::slotCheckMailOnStartup);
854 if (layoutChanged) {
855 layoutSplitters();
858 updateMessageMenu();
859 updateFileMenu();
860 kmkernel->toggleSystemTray();
861 mAccountActionMenu->setAccountOrder(MailCommon::MailCommonSettings::self()->order());
863 connect(Akonadi::AgentManager::self(), &AgentManager::instanceAdded,
864 this, &KMMainWidget::updateFileMenu);
865 connect(Akonadi::AgentManager::self(), &AgentManager::instanceRemoved,
866 this, &KMMainWidget::updateFileMenu);
869 //-----------------------------------------------------------------------------
870 void KMMainWidget::writeConfig(bool force)
872 // Don't save the sizes of all the widgets when we were never shown.
873 // This can happen in Kontact, where the KMail plugin is automatically
874 // loaded, but not necessarily shown.
875 // This prevents invalid sizes from being saved
876 if (mWasEverShown) {
877 // The height of the header widget can be 0, this happens when the user
878 // did not switch to the header widget onced and the "Welcome to KMail"
879 // HTML widget was shown the whole time
880 int headersHeight = mMessagePane->height();
881 if (headersHeight == 0) {
882 headersHeight = height() / 2;
885 KMailSettings::self()->setSearchAndHeaderHeight(headersHeight);
886 KMailSettings::self()->setSearchAndHeaderWidth(mMessagePane->width());
887 if (mFavoriteCollectionsView) {
888 MailCommon::MailCommonSettings::self()->setFavoriteCollectionViewHeight(mFavoriteCollectionsView->height());
889 KMailSettings::self()->setFolderTreeHeight(mFolderTreeWidget->height());
890 if (!mLongFolderList) {
891 KMailSettings::self()->setFolderViewHeight(mFolderViewSplitter->height());
893 } else if (!mLongFolderList && mFolderTreeWidget) {
894 KMailSettings::self()->setFolderTreeHeight(mFolderTreeWidget->height());
896 if (mFolderTreeWidget) {
897 KMailSettings::self()->setFolderViewWidth(mFolderTreeWidget->width());
898 KSharedConfig::Ptr config = KMKernel::self()->config();
899 KConfigGroup group(config, "CollectionFolderView");
901 ETMViewStateSaver saver;
902 saver.setView(mFolderTreeWidget->folderTreeView());
903 saver.saveState(group);
905 group.writeEntry("HeaderState", mFolderTreeWidget->folderTreeView()->header()->saveState());
906 //Work around from startup folder
907 group.deleteEntry("Selection");
908 #if 0
909 if (!KMailSettings::self()->startSpecificFolderAtStartup()) {
910 group.deleteEntry("Current");
912 #endif
913 group.sync();
916 if (mMsgView) {
917 if (!mReaderWindowBelow) {
918 KMailSettings::self()->setReaderWindowWidth(mMsgView->width());
920 mMsgView->viewer()->writeConfig(force);
921 KMailSettings::self()->setReaderWindowHeight(mMsgView->height());
926 void KMMainWidget::writeReaderConfig()
928 if (mWasEverShown) {
929 if (mMsgView) {
930 mMsgView->viewer()->writeConfig();
935 KMReaderWin *KMMainWidget::messageView() const
937 return mMsgView;
940 CollectionPane *KMMainWidget::messageListPane() const
942 return mMessagePane;
945 //-----------------------------------------------------------------------------
946 void KMMainWidget::deleteWidgets()
948 // Simply delete the top splitter, which always is mSplitter1, regardless
949 // of the layout. This deletes all children.
950 // akonadi action manager is created in createWidgets(), parented to this
951 // so not autocleaned up.
952 delete mAkonadiStandardActionManager;
953 mAkonadiStandardActionManager = Q_NULLPTR;
954 delete mSplitter1;
955 mMsgView = Q_NULLPTR;
956 mSearchAndTree = Q_NULLPTR;
957 mFolderViewSplitter = Q_NULLPTR;
958 mFavoriteCollectionsView = Q_NULLPTR;
959 mSplitter1 = Q_NULLPTR;
960 mSplitter2 = Q_NULLPTR;
961 mFavoritesModel = Q_NULLPTR;
964 //-----------------------------------------------------------------------------
965 void KMMainWidget::createWidgets()
967 // Note that all widgets we create in this function have the parent 'this'.
968 // They will be properly reparented in layoutSplitters()
971 // Create header view and search bar
973 FolderTreeWidget::TreeViewOptions opt = FolderTreeWidget::ShowUnreadCount;
974 opt |= FolderTreeWidget::UseLineEditForFiltering;
975 opt |= FolderTreeWidget::ShowCollectionStatisticAnimation;
976 opt |= FolderTreeWidget::DontKeyFilter;
977 mFolderTreeWidget = new FolderTreeWidget(this, mGUIClient, opt);
979 connect(mFolderTreeWidget->folderTreeView(), SIGNAL(currentChanged(Akonadi::Collection)), this, SLOT(slotFolderChanged(Akonadi::Collection)));
981 connect(mFolderTreeWidget->folderTreeView()->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KMMainWidget::updateFolderMenu);
983 connect(mFolderTreeWidget->folderTreeView(), &FolderTreeView::prefereCreateNewTab, this, &KMMainWidget::slotCreateNewTab);
985 mFolderTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
986 mMessagePane = new CollectionPane(!KMailSettings::self()->startSpecificFolderAtStartup(), KMKernel::self()->entityTreeModel(),
987 mFolderTreeWidget->folderTreeView()->selectionModel(),
988 this);
989 connect(KMKernel::self()->entityTreeModel(), &Akonadi::EntityTreeModel::collectionFetched, this, &KMMainWidget::slotCollectionFetched);
991 mMessagePane->setXmlGuiClient(mGUIClient);
992 connect(mMessagePane, &MessageList::Pane::messageSelected,
993 this, &KMMainWidget::slotMessageSelected);
994 connect(mMessagePane, &MessageList::Pane::selectionChanged,
995 this, &KMMainWidget::startUpdateMessageActionsTimer);
996 connect(mMessagePane, &CollectionPane::currentTabChanged, this, &KMMainWidget::refreshMessageListSelection);
997 connect(mMessagePane, &MessageList::Pane::messageActivated,
998 this, &KMMainWidget::slotMessageActivated);
999 connect(mMessagePane, &MessageList::Pane::messageStatusChangeRequest,
1000 this, &KMMainWidget::slotMessageStatusChangeRequest);
1002 connect(mMessagePane, &MessageList::Pane::statusMessage,
1003 BroadcastStatus::instance(), &KPIM::BroadcastStatus::setStatusMsg);
1006 // Create the reader window
1008 if (mReaderWindowActive) {
1009 mMsgView = new KMReaderWin(this, this, actionCollection(), Q_NULLPTR);
1010 if (mMsgActions) {
1011 mMsgActions->setMessageView(mMsgView);
1013 connect(mMsgView->viewer(), &MessageViewer::Viewer::replaceMsgByUnencryptedVersion,
1014 this, &KMMainWidget::slotReplaceMsgByUnencryptedVersion);
1015 connect(mMsgView->viewer(), &MessageViewer::Viewer::popupMenu,
1016 this, &KMMainWidget::slotMessagePopup);
1017 connect(mMsgView->viewer(), &MessageViewer::Viewer::moveMessageToTrash,
1018 this, &KMMainWidget::slotMoveMessageToTrash);
1019 if (mShowIntroductionAction) {
1020 mShowIntroductionAction->setEnabled(true);
1022 } else {
1023 if (mMsgActions) {
1024 mMsgActions->setMessageView(Q_NULLPTR);
1026 if (mShowIntroductionAction) {
1027 mShowIntroductionAction->setEnabled(false);
1032 // Create the folder tree
1033 // the "folder tree" consists of a quicksearch input field and the tree itself
1036 mSearchAndTree = new QWidget(this);
1037 QVBoxLayout *vboxlayout = new QVBoxLayout;
1038 vboxlayout->setMargin(0);
1039 mSearchAndTree->setLayout(vboxlayout);
1041 vboxlayout->addWidget(mFolderTreeWidget);
1043 if (!KMailSettings::self()->enableFolderQuickSearch()) {
1044 mFolderTreeWidget->filterFolderLineEdit()->hide();
1047 // Create the favorite folder view
1049 mAkonadiStandardActionManager = new Akonadi::StandardMailActionManager(mGUIClient->actionCollection(), this);
1050 connect(mAkonadiStandardActionManager, &Akonadi::StandardMailActionManager::actionStateUpdated, this, &KMMainWidget::slotAkonadiStandardActionUpdated);
1052 mAkonadiStandardActionManager->setCollectionSelectionModel(mFolderTreeWidget->folderTreeView()->selectionModel());
1053 mAkonadiStandardActionManager->setItemSelectionModel(mMessagePane->currentItemSelectionModel());
1055 if (mEnableFavoriteFolderView) {
1057 mFavoriteCollectionsView = new FavoriteCollectionWidget(mGUIClient, this);
1058 refreshFavoriteFoldersViewProperties();
1059 connect(mFavoriteCollectionsView, SIGNAL(currentChanged(Akonadi::Collection)), this, SLOT(slotFolderChanged(Akonadi::Collection)));
1061 mFavoritesModel = new Akonadi::FavoriteCollectionsModel(
1062 mFolderTreeWidget->folderTreeView()->model(),
1063 KMKernel::self()->config()->group("FavoriteCollections"), this);
1065 mFavoriteCollectionsView->setModel(mFavoritesModel);
1067 mAkonadiStandardActionManager->setFavoriteCollectionsModel(mFavoritesModel);
1068 mAkonadiStandardActionManager->setFavoriteSelectionModel(mFavoriteCollectionsView->selectionModel());
1071 //Don't use mMailActionManager->createAllActions() to save memory by not
1072 //creating actions that doesn't make sense.
1073 QList<StandardActionManager::Type> standardActions;
1074 standardActions << StandardActionManager::CreateCollection
1075 << StandardActionManager::CopyCollections
1076 << StandardActionManager::DeleteCollections
1077 << StandardActionManager::SynchronizeCollections
1078 << StandardActionManager::CollectionProperties
1079 << StandardActionManager::CopyItems
1080 << StandardActionManager::Paste
1081 << StandardActionManager::DeleteItems
1082 << StandardActionManager::ManageLocalSubscriptions
1083 << StandardActionManager::CopyCollectionToMenu
1084 << StandardActionManager::CopyItemToMenu
1085 << StandardActionManager::MoveItemToMenu
1086 << StandardActionManager::MoveCollectionToMenu
1087 << StandardActionManager::CutItems
1088 << StandardActionManager::CutCollections
1089 << StandardActionManager::CreateResource
1090 << StandardActionManager::DeleteResources
1091 << StandardActionManager::ResourceProperties
1092 << StandardActionManager::SynchronizeResources
1093 << StandardActionManager::ToggleWorkOffline
1094 << StandardActionManager::SynchronizeCollectionsRecursive;
1096 Q_FOREACH (StandardActionManager::Type standardAction, standardActions) {
1097 mAkonadiStandardActionManager->createAction(standardAction);
1100 if (mEnableFavoriteFolderView) {
1101 QList<StandardActionManager::Type> favoriteActions;
1102 favoriteActions << StandardActionManager::AddToFavoriteCollections
1103 << StandardActionManager::RemoveFromFavoriteCollections
1104 << StandardActionManager::RenameFavoriteCollection
1105 << StandardActionManager::SynchronizeFavoriteCollections;
1106 Q_FOREACH (StandardActionManager::Type favoriteAction, favoriteActions) {
1107 mAkonadiStandardActionManager->createAction(favoriteAction);
1111 QList<StandardMailActionManager::Type> mailActions;
1112 mailActions << StandardMailActionManager::MarkAllMailAsRead
1113 << StandardMailActionManager::MoveToTrash
1114 << StandardMailActionManager::MoveAllToTrash
1115 << StandardMailActionManager::RemoveDuplicates
1116 << StandardMailActionManager::EmptyAllTrash
1117 << StandardMailActionManager::MarkMailAsRead
1118 << StandardMailActionManager::MarkMailAsUnread
1119 << StandardMailActionManager::MarkMailAsImportant
1120 << StandardMailActionManager::MarkMailAsActionItem;
1122 Q_FOREACH (StandardMailActionManager::Type mailAction, mailActions) {
1123 mAkonadiStandardActionManager->createAction(mailAction);
1126 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardActionManager::CollectionProperties);
1127 connect(mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CollectionProperties), &QAction::triggered, mManageShowCollectionProperties, &ManageShowCollectionProperties::slotCollectionProperties);
1130 // Create all kinds of actions
1132 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::RemoveDuplicates)->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Asterisk));
1133 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardMailActionManager::RemoveDuplicates);
1134 connect(mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::RemoveDuplicates), &QAction::triggered, this, &KMMainWidget::slotRemoveDuplicates);
1137 mCollectionProperties = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CollectionProperties);
1139 connect(kmkernel->folderCollectionMonitor(), &Monitor::collectionRemoved,
1140 this, &KMMainWidget::slotCollectionRemoved);
1141 connect(kmkernel->folderCollectionMonitor(), &Monitor::itemAdded,
1142 this, &KMMainWidget::slotItemAdded);
1143 connect(kmkernel->folderCollectionMonitor(), &Monitor::itemRemoved,
1144 this, &KMMainWidget::slotItemRemoved);
1145 connect(kmkernel->folderCollectionMonitor(), &Monitor::itemMoved,
1146 this, &KMMainWidget::slotItemMoved);
1147 connect(kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)), SLOT(slotCollectionChanged(Akonadi::Collection,QSet<QByteArray>)));
1149 connect(kmkernel->folderCollectionMonitor(), &Monitor::collectionStatisticsChanged, this, &KMMainWidget::slotCollectionStatisticsChanged);
1153 void KMMainWidget::updateMoveAction(const Akonadi::CollectionStatistics &statistic)
1155 const bool hasUnreadMails = (statistic.unreadCount() > 0);
1156 const bool hasMails = (statistic.count() > 0);
1157 updateMoveAction(hasUnreadMails, hasMails);
1160 void KMMainWidget::updateMoveAction(bool hasUnreadMails, bool hasMails)
1162 const bool enable_goto_unread = hasUnreadMails
1163 || (KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders)
1164 || (KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders);
1165 actionCollection()->action(QStringLiteral("go_next_message"))->setEnabled(hasMails);
1166 actionCollection()->action(QStringLiteral("go_next_unread_message"))->setEnabled(enable_goto_unread);
1167 actionCollection()->action(QStringLiteral("go_prev_message"))->setEnabled(hasMails);
1168 actionCollection()->action(QStringLiteral("go_prev_unread_message"))->setEnabled(enable_goto_unread);
1169 if (mAkonadiStandardActionManager && mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MarkAllMailAsRead)) {
1170 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MarkAllMailAsRead)->setEnabled(hasUnreadMails);
1174 void KMMainWidget::updateAllToTrashAction(int statistics)
1176 bool multiFolder = false;
1177 if (mFolderTreeWidget) {
1178 multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
1180 if (mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)) {
1181 const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural();
1182 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)->setEnabled(folderWithContent
1183 && (statistics > 0)
1184 && mCurrentFolder->canDeleteMessages()
1185 && !multiFolder);
1189 void KMMainWidget::slotCollectionStatisticsChanged(Akonadi::Collection::Id id, const Akonadi::CollectionStatistics &statistic)
1191 if (id == CommonKernel->outboxCollectionFolder().id()) {
1192 const bool enableAction = (statistic.count() > 0);
1193 mSendQueued->setEnabled(enableAction);
1194 mSendActionMenu->setEnabled(enableAction);
1195 } else if (mCurrentFolder && (id == mCurrentFolder->collection().id())) {
1196 updateMoveAction(statistic);
1197 updateAllToTrashAction(statistic.count());
1198 mCurrentFolder->setCollection(MailCommon::Util::updatedCollection(mCurrentFolder->collection()));
1202 void KMMainWidget::slotCreateNewTab(bool preferNewTab)
1204 mMessagePane->setPreferEmptyTab(preferNewTab);
1207 void KMMainWidget::slotCollectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &set)
1209 if (mCurrentFolder
1210 && (collection == mCurrentFolder->collection())
1211 && (set.contains("MESSAGEFOLDER") || set.contains("expirationcollectionattribute"))) {
1212 if (set.contains("MESSAGEFOLDER")) {
1213 mMessagePane->resetModelStorage();
1214 } else {
1215 mCurrentFolder->setCollection(collection);
1217 } else if (set.contains("ENTITYDISPLAY") || set.contains("NAME")) {
1218 const QModelIndex idx = Akonadi::EntityTreeModel::modelIndexForCollection(KMKernel::self()->collectionModel(), collection);
1219 if (idx.isValid()) {
1220 const QString text = idx.data().toString();
1221 const QIcon icon = idx.data(Qt::DecorationRole).value<QIcon>();
1222 mMessagePane->updateTabIconText(collection, text, icon);
1227 void KMMainWidget::slotItemAdded(const Akonadi::Item &msg, const Akonadi::Collection &col)
1229 Q_UNUSED(msg);
1230 if (col.isValid()) {
1231 if (col == CommonKernel->outboxCollectionFolder()) {
1232 startUpdateMessageActionsTimer();
1237 void KMMainWidget::slotItemRemoved(const Akonadi::Item &item)
1239 if (item.isValid() && item.parentCollection().isValid() && (item.parentCollection() == CommonKernel->outboxCollectionFolder())) {
1240 startUpdateMessageActionsTimer();
1244 void KMMainWidget::slotItemMoved(const Akonadi::Item &item, const Akonadi::Collection &from, const Akonadi::Collection &to)
1246 if (item.isValid() && ((from.id() == CommonKernel->outboxCollectionFolder().id())
1247 || to.id() == CommonKernel->outboxCollectionFolder().id())) {
1248 startUpdateMessageActionsTimer();
1252 //-------------------------------------------------------------------------
1253 void KMMainWidget::slotFocusQuickSearch()
1255 const QString text = mMsgView ? mMsgView->copyText() : QString();
1256 mMessagePane->focusQuickSearch(text);
1259 //-------------------------------------------------------------------------
1260 bool KMMainWidget::slotSearch()
1262 if (!mSearchWin) {
1263 mSearchWin = new SearchWindow(this, mCurrentFolder ? mCurrentFolder->collection() : Akonadi::Collection());
1264 mSearchWin->setModal(false);
1265 mSearchWin->setObjectName(QStringLiteral("Search"));
1266 } else {
1267 mSearchWin->activateFolder(mCurrentFolder ? mCurrentFolder->collection() : Akonadi::Collection());
1270 mSearchWin->show();
1271 KWindowSystem::activateWindow(mSearchWin->winId());
1272 return true;
1275 //-----------------------------------------------------------------------------
1276 void KMMainWidget::slotHelp()
1278 KHelpClient::invokeHelp();
1281 //-----------------------------------------------------------------------------
1282 void KMMainWidget::slotFilter()
1284 FilterIf->openFilterDialog(true);
1287 void KMMainWidget::slotManageSieveScripts()
1289 if (!kmkernel->askToGoOnline()) {
1290 return;
1292 if (mManageSieveDialog) {
1293 return;
1296 mManageSieveDialog = new KSieveUi::ManageSieveScriptsDialog;
1297 connect(mManageSieveDialog.data(), &KSieveUi::ManageSieveScriptsDialog::finished, this, &KMMainWidget::slotCheckVacation);
1298 mManageSieveDialog->show();
1301 //-----------------------------------------------------------------------------
1302 void KMMainWidget::slotCheckMail()
1304 kmkernel->checkMail();
1307 //-----------------------------------------------------------------------------
1308 void KMMainWidget::slotCheckMailOnStartup()
1310 kmkernel->checkMailOnStartup();
1313 void KMMainWidget::slotCompose()
1315 KMail::Composer *win;
1316 KMime::Message::Ptr msg(new KMime::Message());
1318 bool forceCursorPosition = false;
1319 if (mCurrentFolder) {
1320 MessageHelper::initHeader(msg, KMKernel::self()->identityManager(), mCurrentFolder->identity());
1321 //Laurent: bug 289905
1323 if ( mCurrentFolder->collection().isValid() && mCurrentFolder->putRepliesInSameFolder() ) {
1324 KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Fcc", msg.get(), QString::number( mCurrentFolder->collection().id() ), "utf-8" );
1325 msg->setHeader( header );
1328 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
1329 parser.setIdentityManager(KMKernel::self()->identityManager());
1330 parser.process(msg, mCurrentFolder->collection());
1331 win = KMail::makeComposer(msg, false, false, KMail::Composer::New, mCurrentFolder->identity());
1332 win->setCollectionForNewMessage(mCurrentFolder->collection());
1333 forceCursorPosition = parser.cursorPositionWasSet();
1334 } else {
1335 MessageHelper::initHeader(msg, KMKernel::self()->identityManager());
1336 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
1337 parser.setIdentityManager(KMKernel::self()->identityManager());
1338 parser.process(KMime::Message::Ptr(), Akonadi::Collection());
1339 win = KMail::makeComposer(msg, false, false, KMail::Composer::New);
1340 forceCursorPosition = parser.cursorPositionWasSet();
1342 if (forceCursorPosition) {
1343 win->setFocusToEditor();
1345 win->show();
1349 //-----------------------------------------------------------------------------
1350 // TODO: do we want the list sorted alphabetically?
1351 void KMMainWidget::slotShowNewFromTemplate()
1353 if (mCurrentFolder) {
1354 const KIdentityManagement::Identity &ident =
1355 kmkernel->identityManager()->identityForUoidOrDefault(mCurrentFolder->identity());
1356 mTemplateFolder = CommonKernel->collectionFromId(ident.templates().toLongLong());
1359 if (!mTemplateFolder.isValid()) {
1360 mTemplateFolder = CommonKernel->templatesCollectionFolder();
1362 if (!mTemplateFolder.isValid()) {
1363 return;
1366 mTemplateMenu->menu()->clear();
1368 Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mTemplateFolder);
1369 job->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent);
1370 job->fetchScope().fetchFullPayload();
1371 connect(job, &Akonadi::ItemFetchJob::result, this, &KMMainWidget::slotDelayedShowNewFromTemplate);
1374 void KMMainWidget::slotDelayedShowNewFromTemplate(KJob *job)
1376 Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob *>(job);
1378 const Akonadi::Item::List items = fetchJob->items();
1379 const int numberOfItems = items.count();
1380 for (int idx = 0; idx < numberOfItems; ++idx) {
1381 KMime::Message::Ptr msg = MessageCore::Util::message(items.at(idx));
1382 if (msg) {
1383 QString subj = msg->subject()->asUnicodeString();
1384 if (subj.isEmpty()) {
1385 subj = i18n("No Subject");
1388 QAction *templateAction = mTemplateMenu->menu()->addAction(KStringHandler::rsqueeze(subj.replace(QLatin1Char('&'), QStringLiteral("&&"))));
1389 QVariant var;
1390 var.setValue(items.at(idx));
1391 templateAction->setData(var);
1395 // If there are no templates available, add a menu entry which informs
1396 // the user about this.
1397 if (mTemplateMenu->menu()->actions().isEmpty()) {
1398 QAction *noAction = mTemplateMenu->menu()->addAction(
1399 i18n("(no templates)"));
1400 noAction->setEnabled(false);
1404 //-----------------------------------------------------------------------------
1405 void KMMainWidget::slotNewFromTemplate(QAction *action)
1408 if (!mTemplateFolder.isValid()) {
1409 return;
1411 const Akonadi::Item item = action->data().value<Akonadi::Item>();
1412 newFromTemplate(item);
1415 //-----------------------------------------------------------------------------
1416 void KMMainWidget::newFromTemplate(const Akonadi::Item &msg)
1418 if (!msg.isValid()) {
1419 return;
1421 KMCommand *command = new KMUseTemplateCommand(this, msg);
1422 command->start();
1425 //-----------------------------------------------------------------------------
1426 void KMMainWidget::slotPostToML()
1428 if (mCurrentFolder && mCurrentFolder->isMailingListEnabled()) {
1429 if (KMail::Util::mailingListPost(mCurrentFolder)) {
1430 return;
1433 slotCompose();
1436 void KMMainWidget::slotExpireFolder()
1438 if (!mCurrentFolder) {
1439 return;
1441 bool mustDeleteExpirationAttribute = false;
1442 MailCommon::ExpireCollectionAttribute *attr = MailCommon::Util::expirationCollectionAttribute(mCurrentFolder->collection(), mustDeleteExpirationAttribute);
1443 bool canBeExpired = true;
1444 if (!attr->isAutoExpire()) {
1445 canBeExpired = false;
1446 } else if (attr->unreadExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever &&
1447 attr->readExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever) {
1448 canBeExpired = false;
1451 if (!canBeExpired) {
1452 const QString message = i18n("This folder does not have any expiry options set");
1453 KMessageBox::information(this, message);
1454 if (mustDeleteExpirationAttribute) {
1455 delete attr;
1457 return;
1460 if (KMailSettings::self()->warnBeforeExpire()) {
1461 const QString message = i18n("<qt>Are you sure you want to expire the folder <b>%1</b>?</qt>",
1462 mCurrentFolder->name().toHtmlEscaped());
1463 if (KMessageBox::warningContinueCancel(this, message, i18n("Expire Folder"),
1464 KGuiItem(i18n("&Expire")))
1465 != KMessageBox::Continue) {
1466 if (mustDeleteExpirationAttribute) {
1467 delete attr;
1469 return;
1473 MailCommon::Util::expireOldMessages(mCurrentFolder->collection(), true /*immediate*/);
1474 if (mustDeleteExpirationAttribute) {
1475 delete attr;
1479 //-----------------------------------------------------------------------------
1480 void KMMainWidget::slotEmptyFolder()
1482 if (!mCurrentFolder) {
1483 return;
1485 const bool isTrash = CommonKernel->folderIsTrash(mCurrentFolder->collection());
1486 if (KMailSettings::self()->confirmBeforeEmpty()) {
1487 const QString title = (isTrash) ? i18n("Empty Trash") : i18n("Move to Trash");
1488 const QString text = (isTrash) ?
1489 i18n("Are you sure you want to empty the trash folder?") :
1490 i18n("<qt>Are you sure you want to move all messages from "
1491 "folder <b>%1</b> to the trash?</qt>", mCurrentFolder->name().toHtmlEscaped());
1493 if (KMessageBox::warningContinueCancel(this, text, title, KGuiItem(title, QStringLiteral("user-trash")))
1494 != KMessageBox::Continue) {
1495 return;
1498 #ifndef QT_NO_CURSOR
1499 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
1500 #endif
1501 slotSelectAllMessages();
1502 if (isTrash) {
1503 /* Don't ask for confirmation again when deleting, the user has already
1504 confirmed. */
1505 slotDeleteMsg(false);
1506 } else {
1507 slotTrashSelectedMessages();
1510 if (mMsgView) {
1511 mMsgView->clearCache();
1514 if (!isTrash) {
1515 BroadcastStatus::instance()->setStatusMsg(i18n("Moved all messages to the trash"));
1518 updateMessageActions();
1520 // Disable empty trash/move all to trash action - we've just deleted/moved
1521 // all folder contents.
1522 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)->setEnabled(false);
1525 //-----------------------------------------------------------------------------
1526 void KMMainWidget::slotArchiveFolder()
1528 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
1529 KMail::ArchiveFolderDialog archiveDialog;
1530 archiveDialog.setFolder(mCurrentFolder->collection());
1531 archiveDialog.exec();
1535 //-----------------------------------------------------------------------------
1536 void KMMainWidget::slotRemoveFolder()
1538 if (!mCurrentFolder) {
1539 return;
1541 if (!mCurrentFolder->collection().isValid()) {
1542 return;
1544 if (mCurrentFolder->isSystemFolder()) {
1545 return;
1547 if (mCurrentFolder->isReadOnly()) {
1548 return;
1551 RemoveCollectionJob *job = new RemoveCollectionJob(this);
1552 connect(job, &RemoveCollectionJob::clearCurrentFolder, this, &KMMainWidget::slotClearCurrentFolder);
1553 job->setMainWidget(this);
1554 job->setCurrentFolder(mCurrentFolder->collection());
1555 job->start();
1558 void KMMainWidget::slotClearCurrentFolder()
1560 mCurrentFolder.clear();
1563 //-----------------------------------------------------------------------------
1564 void KMMainWidget::slotExpireAll()
1566 if (KMailSettings::self()->warnBeforeExpire()) {
1567 const int ret = KMessageBox::warningContinueCancel(KMainWindow::memberList().first(),
1568 i18n("Are you sure you want to expire all old messages?"),
1569 i18n("Expire Old Messages?"), KGuiItem(i18n("Expire")));
1570 if (ret != KMessageBox::Continue) {
1571 return;
1575 kmkernel->expireAllFoldersNow();
1578 //-----------------------------------------------------------------------------
1579 void KMMainWidget::slotOverrideHtmlLoadExt()
1581 if (mHtmlLoadExtGlobalSetting == mFolderHtmlLoadExtPreference) {
1582 int result = KMessageBox::warningContinueCancel(this,
1583 // the warning text is taken from configuredialog.cpp:
1584 i18n("Loading external references in html mail will make you more vulnerable to "
1585 "\"spam\" and may increase the likelihood that your system will be "
1586 "compromised by other present and anticipated security exploits."),
1587 i18n("Security Warning"),
1588 KGuiItem(i18n("Load External References")),
1589 KStandardGuiItem::cancel(),
1590 QStringLiteral("OverrideHtmlLoadExtWarning"), Q_NULLPTR);
1591 if (result == KMessageBox::Cancel) {
1592 mPreferHtmlLoadExtAction->setChecked(false);
1593 return;
1596 mFolderHtmlLoadExtPreference = !mFolderHtmlLoadExtPreference;
1598 if (mMsgView) {
1599 mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
1600 mMsgView->update(true);
1604 //-----------------------------------------------------------------------------
1605 void KMMainWidget::slotMessageQueuedOrDrafted()
1607 if (!CommonKernel->folderIsDraftOrOutbox(mCurrentFolder->collection())) {
1608 return;
1610 if (mMsgView) {
1611 mMsgView->update(true);
1615 //-----------------------------------------------------------------------------
1616 void KMMainWidget::slotForwardInlineMsg()
1618 if (!mCurrentFolder) {
1619 return;
1622 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
1623 if (selectedMessages.isEmpty()) {
1624 return;
1626 KMForwardCommand *command = new KMForwardCommand(
1627 this, selectedMessages, mCurrentFolder->identity()
1630 command->start();
1633 //-----------------------------------------------------------------------------
1634 void KMMainWidget::slotForwardAttachedMsg()
1636 if (!mCurrentFolder) {
1637 return;
1640 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
1641 if (selectedMessages.isEmpty()) {
1642 return;
1644 KMForwardAttachedCommand *command = new KMForwardAttachedCommand(
1645 this, selectedMessages, mCurrentFolder->identity()
1648 command->start();
1651 //-----------------------------------------------------------------------------
1652 void KMMainWidget::slotUseTemplate()
1654 newFromTemplate(mMessagePane->currentItem());
1657 //-----------------------------------------------------------------------------
1658 void KMMainWidget::slotResendMsg()
1660 const Akonadi::Item msg = mMessagePane->currentItem();
1661 if (!msg.isValid()) {
1662 return;
1664 KMCommand *command = new KMResendMessageCommand(this, msg);
1666 command->start();
1669 //-----------------------------------------------------------------------------
1670 // Message moving and permanent deletion
1673 void KMMainWidget::moveMessageSelected(MessageList::Core::MessageItemSetReference ref, const Akonadi::Collection &dest, bool confirmOnDeletion)
1675 Akonadi::Item::List selectMsg = mMessagePane->itemListFromPersistentSet(ref);
1676 // If this is a deletion, ask for confirmation
1677 if (confirmOnDeletion) {
1678 int ret = KMessageBox::warningContinueCancel(
1679 this,
1680 i18np(
1681 "<qt>Do you really want to delete the selected message?<br />"
1682 "Once deleted, it cannot be restored.</qt>",
1683 "<qt>Do you really want to delete the %1 selected messages?<br />"
1684 "Once deleted, they cannot be restored.</qt>",
1685 selectMsg.count()
1687 selectMsg.count() > 1 ? i18n("Delete Messages") : i18n("Delete Message"),
1688 KStandardGuiItem::del(),
1689 KStandardGuiItem::cancel(),
1690 QStringLiteral("NoConfirmDelete")
1692 if (ret == KMessageBox::Cancel) {
1693 mMessagePane->deletePersistentSet(ref);
1694 return; // user canceled the action
1697 mMessagePane->markMessageItemsAsAboutToBeRemoved(ref, true);
1698 // And stuff them into a KMMoveCommand :)
1699 KMMoveCommand *command = new KMMoveCommand(dest, selectMsg, ref);
1700 QObject::connect(
1701 command, &KMMoveCommand::moveDone,
1702 this, &KMMainWidget::slotMoveMessagesCompleted
1704 command->start();
1706 if (dest.isValid()) {
1707 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages..."));
1708 } else {
1709 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages..."));
1713 void KMMainWidget::slotMoveMessagesCompleted(KMMoveCommand *command)
1715 Q_ASSERT(command);
1716 mMessagePane->markMessageItemsAsAboutToBeRemoved(command->refSet(), false);
1717 mMessagePane->deletePersistentSet(command->refSet());
1718 // Bleah :D
1719 const bool moveWasReallyADelete = !command->destFolder().isValid();
1721 if (command->result() == KMCommand::OK) {
1722 if (moveWasReallyADelete) {
1723 BroadcastStatus::instance()->setStatusMsg(i18n("Messages deleted successfully."));
1724 } else {
1725 BroadcastStatus::instance()->setStatusMsg(i18n("Messages moved successfully."));
1727 } else {
1728 if (moveWasReallyADelete) {
1729 if (command->result() == KMCommand::Failed) {
1730 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages failed."));
1731 } else {
1732 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages canceled."));
1734 } else {
1735 if (command->result() == KMCommand::Failed) {
1736 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages failed."));
1737 } else {
1738 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages canceled."));
1742 // The command will autodelete itself and will also kill the set.
1745 void KMMainWidget::slotDeleteMessages()
1747 slotDeleteMsg(true);
1750 void KMMainWidget::slotDeleteMsg(bool confirmDelete)
1752 // Create a persistent message set from the current selection
1753 MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1754 if (ref != -1) {
1755 moveMessageSelected(ref, Akonadi::Collection(), confirmDelete);
1759 void KMMainWidget::slotDeleteThread(bool confirmDelete)
1761 // Create a persistent set from the current thread.
1762 MessageList::Core::MessageItemSetReference ref = mMessagePane->currentThreadAsPersistentSet();
1763 if (ref != -1) {
1764 moveMessageSelected(ref, Akonadi::Collection(), confirmDelete);
1768 FolderSelectionDialog *KMMainWidget::moveOrCopyToDialog()
1770 if (!mMoveOrCopyToDialog) {
1771 FolderSelectionDialog::SelectionFolderOption options = FolderSelectionDialog::HideVirtualFolder;
1772 mMoveOrCopyToDialog = new FolderSelectionDialog(this, options);
1773 mMoveOrCopyToDialog->setModal(true);
1775 return mMoveOrCopyToDialog;
1778 FolderSelectionDialog *KMMainWidget::selectFromAllFoldersDialog()
1780 if (!mSelectFromAllFoldersDialog) {
1781 FolderSelectionDialog::SelectionFolderOptions options = FolderSelectionDialog::None;
1782 options |= FolderSelectionDialog::NotAllowToCreateNewFolder;
1784 mSelectFromAllFoldersDialog = new FolderSelectionDialog(this, options);
1785 mSelectFromAllFoldersDialog->setModal(true);
1787 return mSelectFromAllFoldersDialog;
1790 void KMMainWidget::slotMoveSelectedMessageToFolder()
1792 QPointer<MailCommon::FolderSelectionDialog> dialog(moveOrCopyToDialog());
1793 dialog->setWindowTitle(i18n("Move Messages to Folder"));
1794 if (dialog->exec() && dialog) {
1795 const Akonadi::Collection dest = dialog->selectedCollection();
1796 if (dest.isValid()) {
1797 moveSelectedMessagesToFolder(dest);
1802 void KMMainWidget::moveSelectedMessagesToFolder(const Akonadi::Collection &dest)
1804 MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1805 if (ref != -1) {
1806 //Need to verify if dest == src ??? akonadi do it for us.
1807 moveMessageSelected(ref, dest, false);
1811 void KMMainWidget::copyMessageSelected(const Akonadi::Item::List &selectMsg, const Akonadi::Collection &dest)
1813 if (selectMsg.isEmpty()) {
1814 return;
1816 // And stuff them into a KMCopyCommand :)
1817 KMCommand *command = new KMCopyCommand(dest, selectMsg);
1818 QObject::connect(
1819 command, &KMCommand::completed,
1820 this, &KMMainWidget::slotCopyMessagesCompleted
1822 command->start();
1823 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages..."));
1826 void KMMainWidget::slotCopyMessagesCompleted(KMCommand *command)
1828 Q_ASSERT(command);
1829 if (command->result() == KMCommand::OK) {
1830 BroadcastStatus::instance()->setStatusMsg(i18n("Messages copied successfully."));
1831 } else {
1832 if (command->result() == KMCommand::Failed) {
1833 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages failed."));
1834 } else {
1835 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages canceled."));
1838 // The command will autodelete itself and will also kill the set.
1841 void KMMainWidget::slotCopySelectedMessagesToFolder()
1843 QPointer<MailCommon::FolderSelectionDialog> dialog(moveOrCopyToDialog());
1844 dialog->setWindowTitle(i18n("Copy Messages to Folder"));
1846 if (dialog->exec() && dialog) {
1847 const Akonadi::Collection dest = dialog->selectedCollection();
1848 if (dest.isValid()) {
1849 copySelectedMessagesToFolder(dest);
1854 void KMMainWidget::copySelectedMessagesToFolder(const Akonadi::Collection &dest)
1856 const Akonadi::Item::List lstMsg = mMessagePane->selectionAsMessageItemList();
1857 if (!lstMsg.isEmpty()) {
1858 copyMessageSelected(lstMsg, dest);
1862 //-----------------------------------------------------------------------------
1863 // Message trashing
1865 void KMMainWidget::trashMessageSelected(MessageList::Core::MessageItemSetReference ref)
1867 if (!mCurrentFolder) {
1868 return;
1871 const Akonadi::Item::List select = mMessagePane->itemListFromPersistentSet(ref);
1872 mMessagePane->markMessageItemsAsAboutToBeRemoved(ref, true);
1874 // FIXME: Why we don't use KMMoveCommand( trashFolder(), selectedMessages ); ?
1875 // And stuff them into a KMTrashMsgCommand :)
1876 KMCommand *command = new KMTrashMsgCommand(mCurrentFolder->collection(), select, ref);
1878 QObject::connect(
1879 command, SIGNAL(moveDone(KMMoveCommand*)),
1880 this, SLOT(slotTrashMessagesCompleted(KMMoveCommand*))
1882 command->start();
1883 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash..."));
1886 void KMMainWidget::slotTrashMessagesCompleted(KMMoveCommand *command)
1888 Q_ASSERT(command);
1889 mMessagePane->markMessageItemsAsAboutToBeRemoved(command->refSet(), false);
1890 mMessagePane->deletePersistentSet(command->refSet());
1891 if (command->result() == KMCommand::OK) {
1892 BroadcastStatus::instance()->setStatusMsg(i18n("Messages moved to trash successfully."));
1893 } else {
1894 if (command->result() == KMCommand::Failed) {
1895 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash failed."));
1896 } else {
1897 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash canceled."));
1901 // The command will autodelete itself and will also kill the set.
1904 void KMMainWidget::slotTrashSelectedMessages()
1906 MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet();
1907 if (ref != -1) {
1908 trashMessageSelected(ref);
1912 void KMMainWidget::slotTrashThread()
1914 MessageList::Core::MessageItemSetReference ref = mMessagePane->currentThreadAsPersistentSet();
1915 if (ref != -1) {
1916 trashMessageSelected(ref);
1920 //-----------------------------------------------------------------------------
1921 // Message tag setting for messages
1923 // FIXME: The "selection" version of these functions is in MessageActions.
1924 // We should probably move everything there....
1925 void KMMainWidget::toggleMessageSetTag(const Akonadi::Item::List &select, const Akonadi::Tag &tag)
1927 if (select.isEmpty()) {
1928 return;
1930 KMCommand *command = new KMSetTagCommand(Akonadi::Tag::List() << tag, select, KMSetTagCommand::Toggle);
1931 command->start();
1934 void KMMainWidget::slotSelectMoreMessageTagList()
1936 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
1937 if (selectedMessages.isEmpty()) {
1938 return;
1941 TagSelectDialog dlg(this, selectedMessages.count(), selectedMessages.first());
1942 dlg.setActionCollection(QList<KActionCollection *>() << actionCollection());
1943 if (dlg.exec()) {
1944 const Akonadi::Tag::List lst = dlg.selectedTag();
1945 KMCommand *command = new KMSetTagCommand(lst, selectedMessages, KMSetTagCommand::CleanExistingAndAddNew);
1946 command->start();
1950 void KMMainWidget::slotUpdateMessageTagList(const Akonadi::Tag &tag)
1952 // Create a persistent set from the current thread.
1953 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
1954 if (selectedMessages.isEmpty()) {
1955 return;
1957 toggleMessageSetTag(selectedMessages, tag);
1960 void KMMainWidget::refreshMessageListSelection()
1962 mAkonadiStandardActionManager->setItemSelectionModel(mMessagePane->currentItemSelectionModel());
1963 slotMessageSelected(mMessagePane->currentItem());
1966 //-----------------------------------------------------------------------------
1967 // Status setting for threads
1969 // FIXME: The "selection" version of these functions is in MessageActions.
1970 // We should probably move everything there....
1971 void KMMainWidget::setMessageSetStatus(const Akonadi::Item::List &select,
1972 const Akonadi::MessageStatus &status,
1973 bool toggle)
1975 KMCommand *command = new KMSetStatusCommand(status, select, toggle);
1976 command->start();
1979 void KMMainWidget::setCurrentThreadStatus(const Akonadi::MessageStatus &status, bool toggle)
1981 const Akonadi::Item::List select = mMessagePane->currentThreadAsMessageList();
1982 if (select.isEmpty()) {
1983 return;
1985 setMessageSetStatus(select, status, toggle);
1988 void KMMainWidget::slotSetThreadStatusUnread()
1990 setCurrentThreadStatus(MessageStatus::statusRead(), true);
1993 void KMMainWidget::slotSetThreadStatusImportant()
1995 setCurrentThreadStatus(MessageStatus::statusImportant(), true);
1998 void KMMainWidget::slotSetThreadStatusRead()
2000 setCurrentThreadStatus(MessageStatus::statusRead(), false);
2003 void KMMainWidget::slotSetThreadStatusToAct()
2005 setCurrentThreadStatus(MessageStatus::statusToAct(), true);
2008 void KMMainWidget::slotSetThreadStatusWatched()
2010 setCurrentThreadStatus(MessageStatus::statusWatched(), true);
2011 if (mWatchThreadAction->isChecked()) {
2012 mIgnoreThreadAction->setChecked(false);
2016 void KMMainWidget::slotSetThreadStatusIgnored()
2018 setCurrentThreadStatus(MessageStatus::statusIgnored(), true);
2019 if (mIgnoreThreadAction->isChecked()) {
2020 mWatchThreadAction->setChecked(false);
2024 //-----------------------------------------------------------------------------
2025 void KMMainWidget::slotRedirectMsg()
2027 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2028 if (selectedMessages.isEmpty()) {
2029 return;
2032 KMCommand *command = new KMRedirectCommand(this, selectedMessages);
2033 command->start();
2036 //-----------------------------------------------------------------------------
2037 void KMMainWidget::slotCustomReplyToMsg(const QString &tmpl)
2039 const Akonadi::Item msg = mMessagePane->currentItem();
2040 if (!msg.isValid()) {
2041 return;
2044 const QString text = mMsgView ? mMsgView->copyText() : QString();
2046 qCDebug(KMAIL_LOG) << "Reply with template:" << tmpl;
2048 KMCommand *command = new KMReplyCommand(this,
2049 msg,
2050 MessageComposer::ReplySmart,
2051 text, false,
2052 tmpl);
2053 command->start();
2056 //-----------------------------------------------------------------------------
2057 void KMMainWidget::slotCustomReplyAllToMsg(const QString &tmpl)
2059 const Akonadi::Item msg = mMessagePane->currentItem();
2060 if (!msg.isValid()) {
2061 return;
2064 const QString text = mMsgView ? mMsgView->copyText() : QString();
2066 qCDebug(KMAIL_LOG) << "Reply to All with template:" << tmpl;
2068 KMCommand *command = new KMReplyCommand(this,
2069 msg,
2070 MessageComposer::ReplyAll,
2071 text,
2072 false,
2073 tmpl
2076 command->start();
2079 //-----------------------------------------------------------------------------
2080 void KMMainWidget::slotCustomForwardMsg(const QString &tmpl)
2082 if (!mCurrentFolder) {
2083 return;
2086 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2087 if (selectedMessages.isEmpty()) {
2088 return;
2091 qCDebug(KMAIL_LOG) << "Forward with template:" << tmpl;
2092 KMForwardCommand *command = new KMForwardCommand(
2093 this, selectedMessages, mCurrentFolder->identity(), tmpl
2096 command->start();
2099 void KMMainWidget::openFilterDialog(const QByteArray &field, const QString &value)
2101 FilterIf->openFilterDialog(false);
2102 FilterIf->createFilter(field, value);
2105 //-----------------------------------------------------------------------------
2106 void KMMainWidget::slotSubjectFilter()
2108 const KMime::Message::Ptr msg = mMessagePane->currentMessage();
2109 if (!msg) {
2110 return;
2113 openFilterDialog("Subject", msg->subject()->asUnicodeString());
2116 //-----------------------------------------------------------------------------
2117 void KMMainWidget::slotFromFilter()
2119 KMime::Message::Ptr msg = mMessagePane->currentMessage();
2120 if (!msg) {
2121 return;
2124 AddrSpecList al = MessageHelper::extractAddrSpecs(msg, "From");
2125 if (al.empty()) {
2126 openFilterDialog("From", msg->from()->asUnicodeString());
2127 } else {
2128 openFilterDialog("From", al.front().asString());
2132 //-----------------------------------------------------------------------------
2133 void KMMainWidget::slotToFilter()
2135 KMime::Message::Ptr msg = mMessagePane->currentMessage();
2136 if (!msg) {
2137 return;
2139 openFilterDialog("To", msg->to()->asUnicodeString());
2142 void KMMainWidget::slotCcFilter()
2144 KMime::Message::Ptr msg = mMessagePane->currentMessage();
2145 if (!msg) {
2146 return;
2148 openFilterDialog("Cc", msg->cc()->asUnicodeString());
2151 void KMMainWidget::slotBandwidth(bool b)
2153 PimCommon::NetworkUtil::self()->setLowBandwidth(b);
2156 //-----------------------------------------------------------------------------
2157 void KMMainWidget::slotUndo()
2159 kmkernel->undoStack()->undo();
2160 updateMessageActions();
2161 updateFolderMenu();
2164 //-----------------------------------------------------------------------------
2165 void KMMainWidget::slotJumpToFolder()
2167 QPointer<MailCommon::FolderSelectionDialog> dialog(selectFromAllFoldersDialog());
2168 dialog->setWindowTitle(i18n("Jump to Folder"));
2169 if (dialog->exec() && dialog) {
2170 Akonadi::Collection collection = dialog->selectedCollection();
2171 if (collection.isValid()) {
2172 slotSelectCollectionFolder(collection);
2177 void KMMainWidget::slotSelectCollectionFolder(const Akonadi::Collection &col)
2179 if (mFolderTreeWidget) {
2180 mFolderTreeWidget->selectCollectionFolder(col);
2181 slotFolderChanged(col);
2185 void KMMainWidget::slotApplyFilters()
2187 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2188 if (selectedMessages.isEmpty()) {
2189 return;
2191 applyFilters(selectedMessages);
2194 void KMMainWidget::slotApplyFiltersOnFolder()
2196 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
2197 Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mCurrentFolder->collection(), this);
2198 connect(job, &Akonadi::ItemFetchJob::result, this, &KMMainWidget::slotFetchItemsForFolderDone);
2202 void KMMainWidget::slotFetchItemsForFolderDone(KJob *job)
2204 Akonadi::ItemFetchJob *fjob = dynamic_cast<Akonadi::ItemFetchJob *>(job);
2205 Q_ASSERT(fjob);
2206 Akonadi::Item::List items = fjob->items();
2207 applyFilters(items);
2210 void KMMainWidget::applyFilters(const Akonadi::Item::List &selectedMessages)
2212 #ifndef QT_NO_CURSOR
2213 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
2214 #endif
2216 MailCommon::FilterManager::instance()->filter(selectedMessages);
2219 //-----------------------------------------------------------------------------
2220 void KMMainWidget::slotCheckVacation()
2222 updateVacationScriptStatus(false);
2223 if (!kmkernel->askToGoOnline()) {
2224 return;
2227 mVacationManager->checkVacation();
2228 connect(mVacationManager, SIGNAL(updateVacationScriptStatus(bool,QString)), SLOT(updateVacationScriptStatus(bool,QString)));
2229 connect(mVacationManager, SIGNAL(editVacation()), SLOT(slotEditVacation()));
2232 void KMMainWidget::slotEditVacation(const QString &serverName)
2234 if (!kmkernel->askToGoOnline()) {
2235 return;
2238 mVacationManager->slotEditVacation(serverName);
2241 //-----------------------------------------------------------------------------
2242 void KMMainWidget::slotDebugSieve()
2244 #if !defined(NDEBUG)
2245 if (mSieveDebugDialog) {
2246 return;
2249 mSieveDebugDialog = new KSieveUi::SieveDebugDialog(this);
2250 mSieveDebugDialog->exec();
2251 delete mSieveDebugDialog;
2252 #endif
2255 void KMMainWidget::slotConfigChanged()
2257 readConfig();
2258 mMsgActions->setupForwardActions(actionCollection());
2259 mMsgActions->setupForwardingActionsList(mGUIClient);
2262 //-----------------------------------------------------------------------------
2263 void KMMainWidget::slotSaveMsg()
2265 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2266 if (selectedMessages.isEmpty()) {
2267 return;
2269 KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand(this, selectedMessages);
2270 saveCommand->start();
2273 //-----------------------------------------------------------------------------
2274 void KMMainWidget::slotOpenMsg()
2276 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand(this, QUrl(), overrideEncoding(), this);
2278 openCommand->start();
2281 //-----------------------------------------------------------------------------
2282 void KMMainWidget::slotSaveAttachments()
2284 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
2285 if (selectedMessages.isEmpty()) {
2286 return;
2288 // Avoid re-downloading in the common case that only one message is selected, and the message
2289 // is also displayed in the viewer. For this, create a dummy item without a parent collection / item id,
2290 // so that KMCommand doesn't download it.
2291 KMSaveAttachmentsCommand *saveCommand = Q_NULLPTR;
2292 if (mMsgView && selectedMessages.size() == 1 &&
2293 mMsgView->message().hasPayload<KMime::Message::Ptr>() &&
2294 selectedMessages.first().id() == mMsgView->message().id()) {
2295 Akonadi::Item dummyItem;
2296 dummyItem.setPayload<KMime::Message::Ptr>(mMsgView->message().payload<KMime::Message::Ptr>());
2297 saveCommand = new KMSaveAttachmentsCommand(this, dummyItem, mMsgView->viewer());
2298 } else {
2299 saveCommand = new KMSaveAttachmentsCommand(this, selectedMessages);
2302 saveCommand->start();
2305 void KMMainWidget::slotOnlineStatus()
2307 // KMKernel will Q_EMIT a signal when we toggle the network state that is caught by
2308 // KMMainWidget::slotUpdateOnlineStatus to update our GUI
2309 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Online) {
2310 // if online; then toggle and set it offline.
2311 kmkernel->stopNetworkJobs();
2312 } else {
2313 kmkernel->resumeNetworkJobs();
2314 slotCheckVacation();
2318 void KMMainWidget::slotUpdateOnlineStatus(KMailSettings::EnumNetworkState::type)
2320 if (!mAkonadiStandardActionManager) {
2321 return;
2323 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::ToggleWorkOffline);
2324 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Online) {
2325 action->setText(i18n("Work Offline"));
2326 action->setIcon(QIcon::fromTheme(QStringLiteral("user-offline")));
2327 } else {
2328 action->setText(i18n("Work Online"));
2329 action->setIcon(QIcon::fromTheme(QStringLiteral("user-online")));
2333 //-----------------------------------------------------------------------------
2334 void KMMainWidget::slotSendQueued()
2336 if (kmkernel->msgSender()) {
2337 kmkernel->msgSender()->sendQueued();
2341 //-----------------------------------------------------------------------------
2342 void KMMainWidget::slotSendQueuedVia(MailTransport::Transport *transport)
2344 if (transport) {
2345 if (kmkernel->msgSender()) {
2346 kmkernel->msgSender()->sendQueued(transport->id());
2351 //-----------------------------------------------------------------------------
2352 void KMMainWidget::slotShowBusySplash()
2354 if (mReaderWindowActive) {
2355 mMsgView->displayBusyPage();
2359 void KMMainWidget::showOfflinePage()
2361 if (!mReaderWindowActive) {
2362 return;
2365 mMsgView->displayOfflinePage();
2368 void KMMainWidget::showResourceOfflinePage()
2370 if (!mReaderWindowActive) {
2371 return;
2374 mMsgView->displayResourceOfflinePage();
2377 //-----------------------------------------------------------------------------
2378 void KMMainWidget::slotReplaceMsgByUnencryptedVersion()
2380 qCDebug(KMAIL_LOG);
2381 Akonadi::Item oldMsg = mMessagePane->currentItem();
2382 if (oldMsg.isValid()) {
2383 #if 0
2384 qCDebug(KMAIL_LOG) << "Old message found";
2385 if (oldMsg->hasUnencryptedMsg()) {
2386 qCDebug(KMAIL_LOG) << "Extra unencrypted message found";
2387 KMime::Message *newMsg = oldMsg->unencryptedMsg();
2388 // adjust the message id
2390 QString msgId(oldMsg->msgId());
2391 QString prefix("DecryptedMsg.");
2392 int oldIdx = msgId.indexOf(prefix, 0, Qt::CaseInsensitive);
2393 if (-1 == oldIdx) {
2394 int leftAngle = msgId.lastIndexOf('<');
2395 msgId = msgId.insert((-1 == leftAngle) ? 0 : ++leftAngle, prefix);
2396 } else {
2397 // toggle between "DecryptedMsg." and "DeCryptedMsg."
2398 // to avoid same message id
2399 QCharRef c = msgId[ oldIdx + 2 ];
2400 if ('C' == c) {
2401 c = 'c';
2402 } else {
2403 c = 'C';
2406 newMsg->setMsgId(msgId);
2407 mMsgView->setIdOfLastViewedMessage(msgId);
2409 // insert the unencrypted message
2410 qCDebug(KMAIL_LOG) << "Adding unencrypted message to folder";
2411 mFolder->addMsg(newMsg);
2412 /* Figure out its index in the folder for selecting. This must be count()-1,
2413 * since we append. Be safe and do find, though, just in case. */
2414 int newMsgIdx = mFolder->find(newMsg);
2415 Q_ASSERT(newMsgIdx != -1);
2416 /* we need this unget, to have the message displayed correctly initially */
2417 mFolder->unGetMsg(newMsgIdx);
2418 int idx = mFolder->find(oldMsg);
2419 Q_ASSERT(idx != -1);
2420 /* only select here, so the old one is not un-Gotten before, which would
2421 * render the pointer we hold invalid so that find would fail */
2422 #if 0
2423 // FIXME (Pragma)
2424 mHeaders->setCurrentItemByIndex(newMsgIdx);
2425 #endif
2426 // remove the old one
2427 if (idx != -1) {
2428 qCDebug(KMAIL_LOG) << "Deleting encrypted message";
2429 mFolder->take(idx);
2432 qCDebug(KMAIL_LOG) << "Updating message actions";
2433 updateMessageActions();
2435 qCDebug(KMAIL_LOG) << "Done.";
2436 } else {
2437 qCDebug(KMAIL_LOG) << "NO EXTRA UNENCRYPTED MESSAGE FOUND";
2439 #else
2440 qCDebug(KMAIL_LOG) << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO;
2441 #endif
2442 } else {
2443 qCDebug(KMAIL_LOG) << "PANIC: NO OLD MESSAGE FOUND";
2447 void KMMainWidget::slotFocusOnNextMessage()
2449 mMessagePane->focusNextMessageItem(MessageList::Core::MessageTypeAny, true, false);
2452 void KMMainWidget::slotFocusOnPrevMessage()
2454 mMessagePane->focusPreviousMessageItem(MessageList::Core::MessageTypeAny, true, false);
2457 void KMMainWidget::slotSelectFirstMessage()
2459 mMessagePane->selectFirstMessageItem(MessageList::Core::MessageTypeAny, true);
2462 void KMMainWidget::slotSelectLastMessage()
2464 mMessagePane->selectLastMessageItem(MessageList::Core::MessageTypeAny, true);
2467 void KMMainWidget::slotSelectFocusedMessage()
2469 mMessagePane->selectFocusedMessageItem(true);
2472 void KMMainWidget::slotSelectNextMessage()
2474 mMessagePane->selectNextMessageItem(MessageList::Core::MessageTypeAny,
2475 MessageList::Core::ClearExistingSelection,
2476 true, false);
2479 void KMMainWidget::slotExtendSelectionToNextMessage()
2481 mMessagePane->selectNextMessageItem(
2482 MessageList::Core::MessageTypeAny,
2483 MessageList::Core::GrowOrShrinkExistingSelection,
2484 true, // center item
2485 false // don't loop in folder
2489 void KMMainWidget::slotSelectNextUnreadMessage()
2491 // The looping logic is: "Don't loop" just never loops, "Loop in current folder"
2492 // loops just in current folder, "Loop in all folders" loops in the current folder
2493 // first and then after confirmation jumps to the next folder.
2494 // A bad point here is that if you answer "No, and don't ask me again" to the confirmation
2495 // dialog then you have "Loop in current folder" and "Loop in all folders" that do
2496 // the same thing and no way to get the old behaviour. However, after a consultation on #kontact,
2497 // for bug-to-bug backward compatibility, the masters decided to keep it b0rken :D
2498 // If nobody complains, it stays like it is: if you complain enough maybe the masters will
2499 // decide to reconsider :)
2500 if (!mMessagePane->selectNextMessageItem(
2501 MessageList::Core::MessageTypeUnreadOnly,
2502 MessageList::Core::ClearExistingSelection,
2503 true, // center item
2504 KMailSettings::self()->loopOnGotoUnread() != KMailSettings::EnumLoopOnGotoUnread::DontLoop
2505 )) {
2506 // no next unread message was found in the current folder
2507 if ((KMailSettings::self()->loopOnGotoUnread() ==
2508 KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders) ||
2509 (KMailSettings::self()->loopOnGotoUnread() ==
2510 KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders)) {
2511 mGoToFirstUnreadMessageInSelectedFolder = true;
2512 mFolderTreeWidget->folderTreeView()->selectNextUnreadFolder(true);
2513 mGoToFirstUnreadMessageInSelectedFolder = false;
2518 void KMMainWidget::slotSelectPreviousMessage()
2520 mMessagePane->selectPreviousMessageItem(MessageList::Core::MessageTypeAny,
2521 MessageList::Core::ClearExistingSelection,
2522 true, false);
2525 void KMMainWidget::slotExtendSelectionToPreviousMessage()
2527 mMessagePane->selectPreviousMessageItem(
2528 MessageList::Core::MessageTypeAny,
2529 MessageList::Core::GrowOrShrinkExistingSelection,
2530 true, // center item
2531 false // don't loop in folder
2535 void KMMainWidget::slotSelectPreviousUnreadMessage()
2537 if (!mMessagePane->selectPreviousMessageItem(
2538 MessageList::Core::MessageTypeUnreadOnly,
2539 MessageList::Core::ClearExistingSelection,
2540 true, // center item
2541 KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInCurrentFolder
2542 )) {
2543 // no next unread message was found in the current folder
2544 if ((KMailSettings::self()->loopOnGotoUnread() ==
2545 KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders) ||
2546 (KMailSettings::self()->loopOnGotoUnread() ==
2547 KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders)) {
2548 mGoToFirstUnreadMessageInSelectedFolder = true;
2549 mFolderTreeWidget->folderTreeView()->selectPrevUnreadFolder();
2550 mGoToFirstUnreadMessageInSelectedFolder = false;
2555 void KMMainWidget::slotDisplayCurrentMessage()
2557 if (mMessagePane->currentItem().isValid() && !mMessagePane->searchEditHasFocus()) {
2558 slotMessageActivated(mMessagePane->currentItem());
2562 // Called by double-clicked or 'Enter' in the messagelist -> pop up reader window
2563 void KMMainWidget::slotMessageActivated(const Akonadi::Item &msg)
2565 if (!mCurrentFolder || !msg.isValid()) {
2566 return;
2569 if (CommonKernel->folderIsDraftOrOutbox(mCurrentFolder->collection())) {
2570 mMsgActions->setCurrentMessage(msg);
2571 mMsgActions->editCurrentMessage();
2572 return;
2575 if (CommonKernel->folderIsTemplates(mCurrentFolder->collection())) {
2576 slotUseTemplate();
2577 return;
2580 // Try to fetch the mail, even in offline mode, it might be cached
2581 KMFetchMessageCommand *cmd = new KMFetchMessageCommand(this, msg);
2582 connect(cmd, &KMCommand::completed,
2583 this, &KMMainWidget::slotItemsFetchedForActivation);
2584 cmd->start();
2587 void KMMainWidget::slotItemsFetchedForActivation(KMCommand *command)
2589 KMCommand::Result result = command->result();
2590 if (result != KMCommand::OK) {
2591 qCDebug(KMAIL_LOG) << "Result:" << result;
2592 return;
2595 KMFetchMessageCommand *fetchCmd = qobject_cast<KMFetchMessageCommand *>(command);
2596 const Item msg = fetchCmd->item();
2598 KMReaderMainWin *win = new KMReaderMainWin(mFolderDisplayFormatPreference, mFolderHtmlLoadExtPreference);
2599 const bool useFixedFont = mMsgView ? mMsgView->isFixedFont() :
2600 MessageViewer::MessageViewerSettings::self()->useFixedFont();
2601 win->setUseFixedFont(useFixedFont);
2603 const Akonadi::Collection parentCollection = MailCommon::Util::parentCollectionFromItem(msg);
2604 win->showMessage(overrideEncoding(), msg, parentCollection);
2605 win->show();
2608 void KMMainWidget::slotMessageStatusChangeRequest(const Akonadi::Item &item, const Akonadi::MessageStatus &set, const Akonadi::MessageStatus &clear)
2610 if (!item.isValid()) {
2611 return;
2614 if (clear.toQInt32() != Akonadi::MessageStatus().toQInt32()) {
2615 KMCommand *command = new KMSetStatusCommand(clear, Akonadi::Item::List() << item, true);
2616 command->start();
2619 if (set.toQInt32() != Akonadi::MessageStatus().toQInt32()) {
2620 KMCommand *command = new KMSetStatusCommand(set, Akonadi::Item::List() << item, false);
2621 command->start();
2625 //-----------------------------------------------------------------------------
2626 void KMMainWidget::slotSelectAllMessages()
2628 mMessagePane->selectAll();
2629 updateMessageActions();
2632 void KMMainWidget::slotMessagePopup(const Akonadi::Item &msg, const QUrl &aUrl, const QUrl &imageUrl, const QPoint &aPoint)
2634 updateMessageMenu();
2636 const QString email = KEmailAddress::firstEmailAddress(aUrl.path()).toLower();
2637 if (aUrl.scheme() == QLatin1String("mailto") && !email.isEmpty()) {
2638 Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob(this);
2639 job->setLimit(1);
2640 job->setQuery(Akonadi::ContactSearchJob::Email, email, Akonadi::ContactSearchJob::ExactMatch);
2641 job->setProperty("msg", QVariant::fromValue(msg));
2642 job->setProperty("point", aPoint);
2643 job->setProperty("imageUrl", imageUrl);
2644 job->setProperty("url", aUrl);
2645 connect(job, &Akonadi::ContactSearchJob::result, this, &KMMainWidget::slotContactSearchJobForMessagePopupDone);
2646 } else {
2647 showMessagePopup(msg, aUrl, imageUrl, aPoint, false, false);
2651 void KMMainWidget::slotContactSearchJobForMessagePopupDone(KJob *job)
2653 const Akonadi::ContactSearchJob *searchJob = qobject_cast<Akonadi::ContactSearchJob *>(job);
2654 const bool contactAlreadyExists = !searchJob->contacts().isEmpty();
2656 const Akonadi::Item::List listContact = searchJob->items();
2657 const bool uniqueContactFound = (listContact.count() == 1);
2658 if (uniqueContactFound) {
2659 mMsgView->setContactItem(listContact.first(), searchJob->contacts().at(0));
2660 } else {
2661 mMsgView->clearContactItem();
2663 const Akonadi::Item msg = job->property("msg").value<Akonadi::Item>();
2664 const QPoint aPoint = job->property("point").toPoint();
2665 const QUrl imageUrl = job->property("imageUrl").toUrl();
2666 const QUrl url = job->property("url").toUrl();
2668 showMessagePopup(msg, url, imageUrl, aPoint, contactAlreadyExists, uniqueContactFound);
2671 void KMMainWidget::showMessagePopup(const Akonadi::Item &msg, const QUrl &url, const QUrl &imageUrl, const QPoint &aPoint, bool contactAlreadyExists, bool uniqueContactFound)
2673 QMenu *menu = new QMenu;
2675 bool urlMenuAdded = false;
2677 if (!url.isEmpty()) {
2678 if (url.scheme() == QLatin1String("mailto")) {
2679 // popup on a mailto URL
2680 menu->addAction(mMsgView->mailToComposeAction());
2681 menu->addAction(mMsgView->mailToReplyAction());
2682 menu->addAction(mMsgView->mailToForwardAction());
2684 menu->addSeparator();
2686 if (contactAlreadyExists) {
2687 if (uniqueContactFound) {
2688 menu->addAction(mMsgView->editContactAction());
2689 } else {
2690 menu->addAction(mMsgView->openAddrBookAction());
2692 } else {
2693 menu->addAction(mMsgView->addAddrBookAction());
2694 menu->addAction(mMsgView->addToExistingContactAction());
2696 menu->addSeparator();
2697 menu->addMenu(mMsgView->viewHtmlOption());
2698 menu->addSeparator();
2699 menu->addAction(mMsgView->copyURLAction());
2700 urlMenuAdded = true;
2701 } else if (url.scheme() != QLatin1String("attachment")) {
2702 // popup on a not-mailto URL
2703 menu->addAction(mMsgView->urlOpenAction());
2704 menu->addAction(mMsgView->addBookmarksAction());
2705 menu->addAction(mMsgView->urlSaveAsAction());
2706 menu->addAction(mMsgView->copyURLAction());
2707 menu->addSeparator();
2708 menu->addAction(mMsgView->shareServiceUrlMenu());
2709 if (mMsgView->isAShortUrl(url)) {
2710 menu->addSeparator();
2711 menu->addAction(mMsgView->expandShortUrlAction());
2713 if (!imageUrl.isEmpty()) {
2714 menu->addSeparator();
2715 menu->addAction(mMsgView->copyImageLocation());
2716 menu->addAction(mMsgView->downloadImageToDiskAction());
2717 menu->addAction(mMsgView->shareImage());
2718 if (mMsgView->adblockEnabled()) {
2719 menu->addSeparator();
2720 menu->addAction(mMsgView->blockImage());
2723 urlMenuAdded = true;
2725 qCDebug(KMAIL_LOG) << "URL is:" << url;
2727 const QString selectedText = mMsgView ? mMsgView->copyText() : QString();
2728 if (mMsgView && !selectedText.isEmpty()) {
2729 if (urlMenuAdded) {
2730 menu->addSeparator();
2732 menu->addAction(mMsgActions->replyMenu());
2733 menu->addSeparator();
2735 menu->addAction(mMsgView->copyAction());
2736 menu->addAction(mMsgView->selectAllAction());
2737 menu->addSeparator();
2738 mMsgActions->addWebShortcutsMenu(menu, selectedText);
2739 menu->addSeparator();
2740 menu->addActions(mMsgView->viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedSelection));
2741 if (KPIMTextEdit::TextToSpeech::self()->isReady()) {
2742 menu->addSeparator();
2743 menu->addAction(mMsgView->speakTextAction());
2745 } else if (!urlMenuAdded) {
2746 // popup somewhere else (i.e., not a URL) on the message
2747 if (!mMessagePane->currentMessage()) {
2748 // no messages
2749 delete menu;
2750 return;
2752 Akonadi::Collection parentCol = msg.parentCollection();
2753 if (parentCol.isValid() && CommonKernel->folderIsTemplates(parentCol)) {
2754 menu->addAction(mUseAction);
2755 } else {
2756 menu->addAction(mMsgActions->replyMenu());
2757 menu->addAction(mMsgActions->forwardMenu());
2759 if (parentCol.isValid() && CommonKernel->folderIsSentMailFolder(parentCol)) {
2760 menu->addAction(sendAgainAction());
2761 } else {
2762 menu->addAction(editAction());
2764 menu->addAction(mailingListActionMenu());
2765 menu->addSeparator();
2767 menu->addAction(mCopyActionMenu);
2768 menu->addAction(mMoveActionMenu);
2770 menu->addSeparator();
2772 menu->addAction(mMsgActions->messageStatusMenu());
2773 menu->addSeparator();
2774 if (mMsgView) {
2775 if (!imageUrl.isEmpty()) {
2776 menu->addSeparator();
2777 menu->addAction(mMsgView->copyImageLocation());
2778 menu->addAction(mMsgView->downloadImageToDiskAction());
2779 menu->addAction(mMsgView->shareImage());
2780 menu->addSeparator();
2781 if (mMsgView->adblockEnabled()) {
2782 menu->addAction(mMsgView->blockImage());
2783 menu->addSeparator();
2786 menu->addAction(mMsgView->viewSourceAction());
2787 menu->addAction(mMsgView->toggleFixFontAction());
2788 menu->addAction(mMsgView->toggleMimePartTreeAction());
2790 menu->addSeparator();
2791 if (mMsgActions->printPreviewAction()) {
2792 menu->addAction(mMsgActions->printPreviewAction());
2794 menu->addAction(mMsgActions->printAction());
2795 menu->addAction(mSaveAsAction);
2796 menu->addAction(mSaveAttachmentsAction);
2797 menu->addSeparator();
2798 if (parentCol.isValid() && CommonKernel->folderIsTrash(parentCol)) {
2799 menu->addAction(mDeleteAction);
2800 } else {
2801 menu->addAction(akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash));
2803 menu->addSeparator();
2805 if (mMsgView) {
2806 menu->addActions(mMsgView->viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedMessage));
2807 menu->addSeparator();
2808 menu->addAction(mMsgView->saveMessageDisplayFormatAction());
2809 menu->addAction(mMsgView->resetMessageDisplayFormatAction());
2810 menu->addSeparator();
2812 menu->addAction(mMsgActions->annotateAction());
2814 if (mMsgView && mMsgView->adblockEnabled()) {
2815 menu->addSeparator();
2816 menu->addAction(mMsgView->openBlockableItems());
2818 menu->addSeparator();
2819 menu->addAction(mMsgActions->addFollowupReminderAction());
2820 if (kmkernel->allowToDebugBalooSupport()) {
2821 menu->addSeparator();
2822 menu->addAction(mMsgActions->debugBalooAction());
2825 KAcceleratorManager::manage(menu);
2826 menu->exec(aPoint, Q_NULLPTR);
2827 delete menu;
2830 void KMMainWidget::setupActions()
2832 mMsgActions = new KMail::MessageActions(actionCollection(), this);
2833 mMsgActions->setMessageView(mMsgView);
2835 //----- File Menu
2836 mSaveAsAction = new QAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save &As..."), this);
2837 actionCollection()->addAction(QStringLiteral("file_save_as"), mSaveAsAction);
2838 connect(mSaveAsAction, &QAction::triggered, this, &KMMainWidget::slotSaveMsg);
2839 actionCollection()->setDefaultShortcut(mSaveAsAction, KStandardShortcut::save().first());
2841 mOpenAction = KStandardAction::open(this, SLOT(slotOpenMsg()),
2842 actionCollection());
2844 mOpenRecentAction = KStandardAction::openRecent(this, SLOT(slotOpenRecentMsg(QUrl)),
2845 actionCollection());
2846 KConfigGroup grp = mConfig->group(QStringLiteral("Recent Files"));
2847 mOpenRecentAction->loadEntries(grp);
2850 QAction *action = new QAction(i18n("&Expire All Folders"), this);
2851 actionCollection()->addAction(QStringLiteral("expire_all_folders"), action);
2852 connect(action, &QAction::triggered, this, &KMMainWidget::slotExpireAll);
2855 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("mail-receive")), i18n("Check &Mail"), this);
2856 actionCollection()->addAction(QStringLiteral("check_mail"), action);
2857 connect(action, &QAction::triggered, this, &KMMainWidget::slotCheckMail);
2858 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_L));
2861 mAccountActionMenu = new KActionMenuAccount(this);
2862 mAccountActionMenu->setIcon(QIcon::fromTheme(QStringLiteral("mail-receive")));
2863 mAccountActionMenu->setText(i18n("Check Mail In"));
2865 mAccountActionMenu->setIconText(i18n("Check Mail"));
2866 mAccountActionMenu->setToolTip(i18n("Check Mail"));
2867 actionCollection()->addAction(QStringLiteral("check_mail_in"), mAccountActionMenu);
2868 connect(mAccountActionMenu, &KActionMenu::triggered, this, &KMMainWidget::slotCheckMail);
2870 mSendQueued = new QAction(QIcon::fromTheme(QStringLiteral("mail-send")), i18n("&Send Queued Messages"), this);
2871 actionCollection()->addAction(QStringLiteral("send_queued"), mSendQueued);
2872 connect(mSendQueued, &QAction::triggered, this, &KMMainWidget::slotSendQueued);
2875 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::ToggleWorkOffline);
2876 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardActionManager::ToggleWorkOffline);
2877 action->setCheckable(false);
2878 connect(action, &QAction::triggered, this, &KMMainWidget::slotOnlineStatus);
2879 action->setText(i18n("Online status (unknown)"));
2882 mSendActionMenu = new KActionMenuTransport(this);
2883 mSendActionMenu->setIcon(QIcon::fromTheme(QStringLiteral("mail-send-via")));
2884 mSendActionMenu->setText(i18n("Send Queued Messages Via"));
2885 actionCollection()->addAction(QStringLiteral("send_queued_via"), mSendActionMenu);
2887 connect(mSendActionMenu, &KActionMenuTransport::transportSelected, this, &KMMainWidget::slotSendQueuedVia);
2889 //----- Tools menu
2890 if (parent()->inherits("KMMainWin")) {
2891 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("x-office-address-book")), i18n("&Address Book"), this);
2892 actionCollection()->addAction(QStringLiteral("addressbook"), action);
2893 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotAddrBook);
2894 if (QStandardPaths::findExecutable(QStringLiteral("kaddressbook")).isEmpty()) {
2895 action->setEnabled(false);
2900 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("pgp-keys")), i18n("Certificate Manager"), this);
2901 actionCollection()->addAction(QStringLiteral("tools_start_certman"), action);
2902 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotStartCertManager);
2903 // disable action if no certman binary is around
2904 if (QStandardPaths::findExecutable(QStringLiteral("kleopatra")).isEmpty()) {
2905 action->setEnabled(false);
2909 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("pgp-keys")), i18n("GnuPG Log Viewer"), this);
2910 actionCollection()->addAction(QStringLiteral("tools_start_kwatchgnupg"), action);
2911 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotStartWatchGnuPG);
2912 #ifdef Q_OS_WIN32
2913 // not ported yet, underlying infrastructure missing on Windows
2914 const bool usableKWatchGnupg = false;
2915 #else
2916 // disable action if no kwatchgnupg binary is around
2917 bool usableKWatchGnupg = !QStandardPaths::findExecutable(QStringLiteral("kwatchgnupg")).isEmpty();
2918 #endif
2919 action->setEnabled(usableKWatchGnupg);
2922 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("document-import")), i18n("&Import Messages..."), this);
2923 actionCollection()->addAction(QStringLiteral("import"), action);
2924 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotImport);
2925 if (QStandardPaths::findExecutable(QStringLiteral("importwizard")).isEmpty()) {
2926 action->setEnabled(false);
2930 #if !defined(NDEBUG)
2932 QAction *action = new QAction(i18n("&Debug Sieve..."), this);
2933 actionCollection()->addAction(QStringLiteral("tools_debug_sieve"), action);
2934 connect(action, &QAction::triggered, this, &KMMainWidget::slotDebugSieve);
2936 #endif
2939 QAction *action = new QAction(i18n("Filter &Log Viewer..."), this);
2940 actionCollection()->addAction(QStringLiteral("filter_log_viewer"), action);
2941 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotFilterLogViewer);
2944 QAction *action = new QAction(i18n("&Anti-Spam Wizard..."), this);
2945 actionCollection()->addAction(QStringLiteral("antiSpamWizard"), action);
2946 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotAntiSpamWizard);
2949 QAction *action = new QAction(i18n("&Anti-Virus Wizard..."), this);
2950 actionCollection()->addAction(QStringLiteral("antiVirusWizard"), action);
2951 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotAntiVirusWizard);
2954 QAction *action = new QAction(i18n("&Account Wizard..."), this);
2955 actionCollection()->addAction(QStringLiteral("accountWizard"), action);
2956 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotAccountWizard);
2959 QAction *action = new QAction(i18n("&Import Wizard..."), this);
2960 actionCollection()->addAction(QStringLiteral("importWizard"), action);
2961 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotImportWizard);
2963 if (KSieveUi::Util::allowOutOfOfficeSettings()) {
2964 QAction *action = new QAction(i18n("Edit \"Out of Office\" Replies..."), this);
2965 actionCollection()->addAction(QStringLiteral("tools_edit_vacation"), action);
2966 connect(action, SIGNAL(triggered(bool)), SLOT(slotEditVacation()));
2970 QAction *action = new QAction(i18n("&Configure Automatic Archiving..."), this);
2971 actionCollection()->addAction(QStringLiteral("tools_automatic_archiving"), action);
2972 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotConfigureAutomaticArchiving);
2976 QAction *action = new QAction(i18n("Delayed Messages..."), this);
2977 actionCollection()->addAction(QStringLiteral("message_delayed"), action);
2978 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotConfigureSendLater);
2982 QAction *action = new QAction(i18n("Followup Reminder Messages..."), this);
2983 actionCollection()->addAction(QStringLiteral("followup_reminder_messages"), action);
2984 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotConfigureFollowupReminder);
2987 // Disable the standard action delete key sortcut.
2988 QAction *const standardDelAction = akonadiStandardAction(Akonadi::StandardActionManager::DeleteItems);
2989 standardDelAction->setShortcut(QKeySequence());
2991 //----- Edit Menu
2993 /* The delete action is nowhere in the gui, by default, so we need to make
2994 * sure it is plugged into the KAccel now, since that won't happen on
2995 * XMLGui construction or manual ->plug(). This is only a problem when run
2996 * as a part, though. */
2997 mDeleteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@action Hard delete, bypassing trash", "&Delete"), this);
2998 actionCollection()->addAction(QStringLiteral("delete"), mDeleteAction);
2999 connect(mDeleteAction, &QAction::triggered, this, &KMMainWidget::slotDeleteMessages);
3000 actionCollection()->setDefaultShortcut(mDeleteAction, QKeySequence(Qt::SHIFT + Qt::Key_Delete));
3002 mTrashThreadAction = new QAction(i18n("M&ove Thread to Trash"), this);
3003 actionCollection()->addAction(QStringLiteral("move_thread_to_trash"), mTrashThreadAction);
3004 actionCollection()->setDefaultShortcut(mTrashThreadAction, QKeySequence(Qt::CTRL + Qt::Key_Delete));
3005 mTrashThreadAction->setIcon(QIcon::fromTheme(QStringLiteral("user-trash")));
3006 KMail::Util::addQActionHelpText(mTrashThreadAction, i18n("Move thread to trashcan"));
3007 connect(mTrashThreadAction, &QAction::triggered, this, &KMMainWidget::slotTrashThread);
3009 mDeleteThreadAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete T&hread"), this);
3010 actionCollection()->addAction(QStringLiteral("delete_thread"), mDeleteThreadAction);
3011 //Don't use new connect api.
3012 connect(mDeleteThreadAction, SIGNAL(triggered(bool)), this, SLOT(slotDeleteThread()));
3013 actionCollection()->setDefaultShortcut(mDeleteThreadAction, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete));
3015 mSearchMessages = new QAction(QIcon::fromTheme(QStringLiteral("edit-find-mail")), i18n("&Find Messages..."), this);
3016 actionCollection()->addAction(QStringLiteral("search_messages"), mSearchMessages);
3017 connect(mSearchMessages, &QAction::triggered, this, &KMMainWidget::slotRequestFullSearchFromQuickSearch);
3018 actionCollection()->setDefaultShortcut(mSearchMessages, QKeySequence(Qt::Key_S));
3021 QAction *action = new QAction(i18n("Select &All Messages"), this);
3022 actionCollection()->addAction(QStringLiteral("mark_all_messages"), action);
3023 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectAllMessages);
3024 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_A));
3027 //----- Folder Menu
3029 mFolderMailingListPropertiesAction = new QAction(i18n("&Mailing List Management..."), this);
3030 actionCollection()->addAction(QStringLiteral("folder_mailinglist_properties"), mFolderMailingListPropertiesAction);
3031 connect(mFolderMailingListPropertiesAction, &QAction::triggered, mManageShowCollectionProperties, &ManageShowCollectionProperties::slotFolderMailingListProperties);
3032 // mFolderMailingListPropertiesAction->setIcon(QIcon::fromTheme("document-properties-mailing-list"));
3034 mShowFolderShortcutDialogAction = new QAction(QIcon::fromTheme(QStringLiteral("configure-shortcuts")), i18n("&Assign Shortcut..."), this);
3035 actionCollection()->addAction(QStringLiteral("folder_shortcut_command"), mShowFolderShortcutDialogAction);
3036 connect(mShowFolderShortcutDialogAction, &QAction::triggered, mManageShowCollectionProperties,
3037 &ManageShowCollectionProperties::slotShowFolderShortcutDialog);
3038 // FIXME: this action is not currently enabled in the rc file, but even if
3039 // it were there is inconsistency between the action name and action.
3040 // "Expiration Settings" implies that this will lead to a settings dialogue
3041 // and it should be followed by a "...", but slotExpireFolder() performs
3042 // an immediate expiry.
3044 // TODO: expire action should be disabled if there is no content or if
3045 // the folder can't delete messages.
3047 // Leaving the action here for the moment, it and the "Expire" option in the
3048 // folder popup menu should be combined or at least made consistent. Same for
3049 // slotExpireFolder() and FolderViewItem::slotShowExpiryProperties().
3050 mExpireFolderAction = new QAction(i18n("&Expiration Settings"), this);
3051 actionCollection()->addAction(QStringLiteral("expire"), mExpireFolderAction);
3052 connect(mExpireFolderAction, &QAction::triggered, this, &KMMainWidget::slotExpireFolder);
3054 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardMailActionManager::MoveToTrash);
3055 connect(mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveToTrash), &QAction::triggered, this, &KMMainWidget::slotTrashSelectedMessages);
3057 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardMailActionManager::MoveAllToTrash);
3058 connect(mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash), &QAction::triggered, this, &KMMainWidget::slotEmptyFolder);
3060 mAkonadiStandardActionManager->interceptAction(Akonadi::StandardActionManager::DeleteCollections);
3061 connect(mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::DeleteCollections), &QAction::triggered, this, &KMMainWidget::slotRemoveFolder);
3063 // ### PORT ME: Add this to the context menu. Not possible right now because
3064 // the context menu uses XMLGUI, and that would add the entry to
3065 // all collection context menus
3066 mArchiveFolderAction = new QAction(i18n("&Archive Folder..."), this);
3067 actionCollection()->addAction(QStringLiteral("archive_folder"), mArchiveFolderAction);
3068 connect(mArchiveFolderAction, &QAction::triggered, this, &KMMainWidget::slotArchiveFolder);
3070 mDisplayMessageFormatMenu = new DisplayMessageFormatActionMenu(this);
3071 connect(mDisplayMessageFormatMenu, &DisplayMessageFormatActionMenu::changeDisplayMessageFormat, this, &KMMainWidget::slotChangeDisplayMessageFormat);
3072 actionCollection()->addAction(QStringLiteral("display_format_message"), mDisplayMessageFormatMenu);
3074 mPreferHtmlLoadExtAction = new KToggleAction(i18n("Load E&xternal References"), this);
3075 actionCollection()->addAction(QStringLiteral("prefer_html_external_refs"), mPreferHtmlLoadExtAction);
3076 connect(mPreferHtmlLoadExtAction, &KToggleAction::triggered, this, &KMMainWidget::slotOverrideHtmlLoadExt);
3079 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyCollections);
3080 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::CTRL + Qt::Key_C));
3083 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::Paste);
3084 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::CTRL + Qt::Key_V));
3087 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyItems);
3088 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::CTRL + Qt::Key_C));
3091 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CutItems);
3092 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::CTRL + Qt::Key_X));
3096 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyItemToMenu);
3097 action->setText(i18n("Copy Message To..."));
3098 action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::MoveItemToMenu);
3099 action->setText(i18n("Move Message To..."));
3102 //----- Message Menu
3104 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("mail-message-new")), i18n("&New Message..."), this);
3105 actionCollection()->addAction(QStringLiteral("new_message"), action);
3106 action->setIconText(i18nc("@action:intoolbar New Empty Message", "New"));
3107 connect(action, &QAction::triggered, this, &KMMainWidget::slotCompose);
3108 // do not set a New shortcut if kmail is a component
3109 if (!kmkernel->xmlGuiInstanceName().isEmpty()) {
3110 actionCollection()->setDefaultShortcut(action, KStandardShortcut::openNew().first());
3114 mTemplateMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("document-new")), i18n("Message From &Template"),
3115 actionCollection());
3116 mTemplateMenu->setDelayed(true);
3117 actionCollection()->addAction(QStringLiteral("new_from_template"), mTemplateMenu);
3118 connect(mTemplateMenu->menu(), &QMenu::aboutToShow, this,
3119 &KMMainWidget::slotShowNewFromTemplate);
3120 connect(mTemplateMenu->menu(), &QMenu::triggered, this,
3121 &KMMainWidget::slotNewFromTemplate);
3123 mMessageNewList = new QAction(QIcon::fromTheme(QStringLiteral("mail-message-new-list")),
3124 i18n("New Message t&o Mailing-List..."),
3125 this);
3126 actionCollection()->addAction(QStringLiteral("post_message"), mMessageNewList);
3127 connect(mMessageNewList, &QAction::triggered,
3128 this, &KMMainWidget::slotPostToML);
3129 actionCollection()->setDefaultShortcut(mMessageNewList, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_N));
3131 mSendAgainAction = new QAction(i18n("Send A&gain..."), this);
3132 actionCollection()->addAction(QStringLiteral("send_again"), mSendAgainAction);
3133 connect(mSendAgainAction, &QAction::triggered, this, &KMMainWidget::slotResendMsg);
3135 //----- Create filter actions
3136 mFilterMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("&Create Filter"), this);
3137 actionCollection()->addAction(QStringLiteral("create_filter"), mFilterMenu);
3138 connect(mFilterMenu, &QAction::triggered, this,
3139 &KMMainWidget::slotFilter);
3141 QAction *action = new QAction(i18n("Filter on &Subject..."), this);
3142 actionCollection()->addAction(QStringLiteral("subject_filter"), action);
3143 connect(action, &QAction::triggered, this, &KMMainWidget::slotSubjectFilter);
3144 mFilterMenu->addAction(action);
3148 QAction *action = new QAction(i18n("Filter on &From..."), this);
3149 actionCollection()->addAction(QStringLiteral("from_filter"), action);
3150 connect(action, &QAction::triggered, this, &KMMainWidget::slotFromFilter);
3151 mFilterMenu->addAction(action);
3154 QAction *action = new QAction(i18n("Filter on &To..."), this);
3155 actionCollection()->addAction(QStringLiteral("to_filter"), action);
3156 connect(action, &QAction::triggered, this, &KMMainWidget::slotToFilter);
3157 mFilterMenu->addAction(action);
3160 QAction *action = new QAction(i18n("Filter on &Cc..."), this);
3161 actionCollection()->addAction(QStringLiteral("cc_filter"), action);
3162 connect(action, &QAction::triggered, this, &KMMainWidget::slotCcFilter);
3163 mFilterMenu->addAction(action);
3165 mFilterMenu->addAction(mMsgActions->listFilterAction());
3167 mUseAction = new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("New Message From &Template"), this);
3168 actionCollection()->addAction(QStringLiteral("use_template"), mUseAction);
3169 connect(mUseAction, &QAction::triggered, this, &KMMainWidget::slotUseTemplate);
3170 actionCollection()->setDefaultShortcut(mUseAction, QKeySequence(Qt::SHIFT + Qt::Key_N));
3172 //----- "Mark Thread" submenu
3173 mThreadStatusMenu = new KActionMenu(i18n("Mark &Thread"), this);
3174 actionCollection()->addAction(QStringLiteral("thread_status"), mThreadStatusMenu);
3176 mMarkThreadAsReadAction = new QAction(QIcon::fromTheme(QStringLiteral("mail-mark-read")), i18n("Mark Thread as &Read"), this);
3177 actionCollection()->addAction(QStringLiteral("thread_read"), mMarkThreadAsReadAction);
3178 connect(mMarkThreadAsReadAction, &QAction::triggered, this, &KMMainWidget::slotSetThreadStatusRead);
3179 KMail::Util::addQActionHelpText(mMarkThreadAsReadAction, i18n("Mark all messages in the selected thread as read"));
3180 mThreadStatusMenu->addAction(mMarkThreadAsReadAction);
3182 mMarkThreadAsUnreadAction = new QAction(QIcon::fromTheme(QStringLiteral("mail-mark-unread")), i18n("Mark Thread as &Unread"), this);
3183 actionCollection()->addAction(QStringLiteral("thread_unread"), mMarkThreadAsUnreadAction);
3184 connect(mMarkThreadAsUnreadAction, &QAction::triggered, this, &KMMainWidget::slotSetThreadStatusUnread);
3185 KMail::Util::addQActionHelpText(mMarkThreadAsUnreadAction, i18n("Mark all messages in the selected thread as unread"));
3186 mThreadStatusMenu->addAction(mMarkThreadAsUnreadAction);
3188 mThreadStatusMenu->addSeparator();
3190 //----- "Mark Thread" toggle actions
3191 mToggleThreadImportantAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-mark-important")), i18n("Mark Thread as &Important"), this);
3192 actionCollection()->addAction(QStringLiteral("thread_flag"), mToggleThreadImportantAction);
3193 connect(mToggleThreadImportantAction, &KToggleAction::triggered, this, &KMMainWidget::slotSetThreadStatusImportant);
3194 mToggleThreadImportantAction->setCheckedState(KGuiItem(i18n("Remove &Important Thread Mark")));
3195 mThreadStatusMenu->addAction(mToggleThreadImportantAction);
3197 mToggleThreadToActAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-mark-task")), i18n("Mark Thread as &Action Item"), this);
3198 actionCollection()->addAction(QStringLiteral("thread_toact"), mToggleThreadToActAction);
3199 connect(mToggleThreadToActAction, &KToggleAction::triggered, this, &KMMainWidget::slotSetThreadStatusToAct);
3200 mToggleThreadToActAction->setCheckedState(KGuiItem(i18n("Remove &Action Item Thread Mark")));
3201 mThreadStatusMenu->addAction(mToggleThreadToActAction);
3203 //------- "Watch and ignore thread" actions
3204 mWatchThreadAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-thread-watch")), i18n("&Watch Thread"), this);
3205 actionCollection()->addAction(QStringLiteral("thread_watched"), mWatchThreadAction);
3206 connect(mWatchThreadAction, &KToggleAction::triggered, this, &KMMainWidget::slotSetThreadStatusWatched);
3208 mIgnoreThreadAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-thread-ignored")), i18n("&Ignore Thread"), this);
3209 actionCollection()->addAction(QStringLiteral("thread_ignored"), mIgnoreThreadAction);
3210 connect(mIgnoreThreadAction, &KToggleAction::triggered, this, &KMMainWidget::slotSetThreadStatusIgnored);
3212 mThreadStatusMenu->addSeparator();
3213 mThreadStatusMenu->addAction(mWatchThreadAction);
3214 mThreadStatusMenu->addAction(mIgnoreThreadAction);
3216 mSaveAttachmentsAction = new QAction(QIcon::fromTheme(QStringLiteral("mail-attachment")), i18n("Save A&ttachments..."), this);
3217 actionCollection()->addAction(QStringLiteral("file_save_attachments"), mSaveAttachmentsAction);
3218 connect(mSaveAttachmentsAction, &QAction::triggered, this, &KMMainWidget::slotSaveAttachments);
3220 mMoveActionMenu = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::MoveItemToMenu);
3222 mCopyActionMenu = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyItemToMenu);
3224 mApplyAllFiltersAction =
3225 new QAction(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("Appl&y All Filters"), this);
3226 actionCollection()->addAction(QStringLiteral("apply_filters"), mApplyAllFiltersAction);
3227 connect(mApplyAllFiltersAction, &QAction::triggered,
3228 this, &KMMainWidget::slotApplyFilters);
3229 actionCollection()->setDefaultShortcut(mApplyAllFiltersAction, QKeySequence(Qt::CTRL + Qt::Key_J));
3231 mApplyFilterActionsMenu = new KActionMenu(i18n("A&pply Filter"), this);
3232 actionCollection()->addAction(QStringLiteral("apply_filter_actions"), mApplyFilterActionsMenu);
3235 QAction *action = new QAction(i18nc("View->", "&Expand Thread / Group"), this);
3236 actionCollection()->addAction(QStringLiteral("expand_thread"), action);
3237 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Period));
3238 KMail::Util::addQActionHelpText(action, i18n("Expand the current thread or group"));
3239 connect(action, &QAction::triggered, this, &KMMainWidget::slotExpandThread);
3242 QAction *action = new QAction(i18nc("View->", "&Collapse Thread / Group"), this);
3243 actionCollection()->addAction(QStringLiteral("collapse_thread"), action);
3244 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Comma));
3245 KMail::Util::addQActionHelpText(action, i18n("Collapse the current thread or group"));
3246 connect(action, &QAction::triggered, this, &KMMainWidget::slotCollapseThread);
3249 QAction *action = new QAction(i18nc("View->", "Ex&pand All Threads"), this);
3250 actionCollection()->addAction(QStringLiteral("expand_all_threads"), action);
3251 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Period));
3252 KMail::Util::addQActionHelpText(action, i18n("Expand all threads in the current folder"));
3253 connect(action, &QAction::triggered, this, &KMMainWidget::slotExpandAllThreads);
3256 QAction *action = new QAction(i18nc("View->", "C&ollapse All Threads"), this);
3257 actionCollection()->addAction(QStringLiteral("collapse_all_threads"), action);
3258 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Comma));
3259 KMail::Util::addQActionHelpText(action, i18n("Collapse all threads in the current folder"));
3260 connect(action, &QAction::triggered, this, &KMMainWidget::slotCollapseAllThreads);
3263 QAction *dukeOfMonmoth = new QAction(i18n("&Display Message"), this);
3264 actionCollection()->addAction(QStringLiteral("display_message"), dukeOfMonmoth);
3265 connect(dukeOfMonmoth, &QAction::triggered, this, &KMMainWidget::slotDisplayCurrentMessage);
3266 QList<QKeySequence> shortcuts;
3267 shortcuts << QKeySequence(Qt::Key_Enter) << QKeySequence(Qt::Key_Return);
3268 actionCollection()->setDefaultShortcuts(dukeOfMonmoth, shortcuts);
3270 //----- Go Menu
3272 QAction *action = new QAction(i18n("&Next Message"), this);
3273 actionCollection()->addAction(QStringLiteral("go_next_message"), action);
3274 actionCollection()->setDefaultShortcut(action, QKeySequence(QStringLiteral("N; Right")));
3275 KMail::Util::addQActionHelpText(action, i18n("Go to the next message"));
3276 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectNextMessage);
3279 QAction *action = new QAction(i18n("Next &Unread Message"), this);
3280 actionCollection()->addAction(QStringLiteral("go_next_unread_message"), action);
3281 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(Qt::Key_Plus) << QKeySequence(Qt::Key_Plus + Qt::KeypadModifier));
3282 if (QApplication::isRightToLeft()) {
3283 action->setIcon(QIcon::fromTheme(QStringLiteral("go-previous")));
3284 } else {
3285 action->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
3287 action->setIconText(i18nc("@action:inmenu Goto next unread message", "Next"));
3288 KMail::Util::addQActionHelpText(action, i18n("Go to the next unread message"));
3289 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectNextUnreadMessage);
3292 QAction *action = new QAction(i18n("&Previous Message"), this);
3293 actionCollection()->addAction(QStringLiteral("go_prev_message"), action);
3294 KMail::Util::addQActionHelpText(action, i18n("Go to the previous message"));
3295 actionCollection()->setDefaultShortcut(action, QKeySequence(QStringLiteral("P; Left")));
3296 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectPreviousMessage);
3299 QAction *action = new QAction(i18n("Previous Unread &Message"), this);
3300 actionCollection()->addAction(QStringLiteral("go_prev_unread_message"), action);
3301 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(Qt::Key_Minus) << QKeySequence(Qt::Key_Minus + Qt::KeypadModifier));
3302 if (QApplication::isRightToLeft()) {
3303 action->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
3304 } else {
3305 action->setIcon(QIcon::fromTheme(QStringLiteral("go-previous")));
3307 action->setIconText(i18nc("@action:inmenu Goto previous unread message.", "Previous"));
3308 KMail::Util::addQActionHelpText(action, i18n("Go to the previous unread message"));
3309 connect(action, &QAction::triggered, this, &KMMainWidget::slotSelectPreviousUnreadMessage);
3312 QAction *action = new QAction(i18n("Next Unread &Folder"), this);
3313 actionCollection()->addAction(QStringLiteral("go_next_unread_folder"), action);
3314 connect(action, &QAction::triggered, this, &KMMainWidget::slotNextUnreadFolder);
3315 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Plus) << QKeySequence(Qt::ALT + Qt::Key_Plus + Qt::KeypadModifier));
3316 KMail::Util::addQActionHelpText(action, i18n("Go to the next folder with unread messages"));
3319 QAction *action = new QAction(i18n("Previous Unread F&older"), this);
3320 actionCollection()->addAction(QStringLiteral("go_prev_unread_folder"), action);
3321 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Minus) << QKeySequence(Qt::ALT + Qt::Key_Minus + Qt::KeypadModifier));
3322 KMail::Util::addQActionHelpText(action, i18n("Go to the previous folder with unread messages"));
3323 connect(action, &QAction::triggered, this, &KMMainWidget::slotPrevUnreadFolder);
3326 QAction *action = new QAction(i18nc("Go->", "Next Unread &Text"), this);
3327 actionCollection()->addAction(QStringLiteral("go_next_unread_text"), action);
3328 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Space));
3329 KMail::Util::addQActionHelpText(action, i18n("Go to the next unread text"));
3330 action->setWhatsThis(i18n("Scroll down current message. "
3331 "If at end of current message, "
3332 "go to next unread message."));
3333 connect(action, &QAction::triggered, this, &KMMainWidget::slotReadOn);
3336 //----- Settings Menu
3338 QAction *action = new QAction(i18n("Configure &Filters..."), this);
3339 action->setMenuRole(QAction::NoRole); // do not move to application menu on OS X
3340 actionCollection()->addAction(QStringLiteral("filter"), action);
3341 connect(action, &QAction::triggered, this, &KMMainWidget::slotFilter);
3344 QAction *action = new QAction(i18n("Manage &Sieve Scripts..."), this);
3345 actionCollection()->addAction(QStringLiteral("sieveFilters"), action);
3346 connect(action, &QAction::triggered, this, &KMMainWidget::slotManageSieveScripts);
3349 mShowIntroductionAction = new QAction(QIcon::fromTheme(QStringLiteral("kmail")), i18n("KMail &Introduction"), this);
3350 actionCollection()->addAction(QStringLiteral("help_kmail_welcomepage"), mShowIntroductionAction);
3351 KMail::Util::addQActionHelpText(mShowIntroductionAction, i18n("Display KMail's Welcome Page"));
3352 connect(mShowIntroductionAction, &QAction::triggered, this, &KMMainWidget::slotIntro);
3353 mShowIntroductionAction->setEnabled(mMsgView != Q_NULLPTR);
3356 // ----- Standard Actions
3358 // KStandardAction::configureNotifications(this, SLOT(slotEditNotifications()), actionCollection());
3360 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("preferences-desktop-notification")),
3361 i18n("Configure &Notifications..."), this);
3362 action->setMenuRole(QAction::NoRole); // do not move to application menu on OS X
3363 actionCollection()->addAction(QStringLiteral("kmail_configure_notifications"), action);
3364 connect(action, &QAction::triggered, this, &KMMainWidget::slotEditNotifications);
3368 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("&Configure KMail..."), this);
3369 action->setMenuRole(QAction::PreferencesRole); // this one should move to the application menu on OS X
3370 actionCollection()->addAction(QStringLiteral("kmail_configure_kmail"), action);
3371 connect(action, &QAction::triggered, kmkernel, &KMKernel::slotShowConfigurationDialog);
3375 mExpireConfigAction = new QAction(i18n("Expire..."), this);
3376 actionCollection()->addAction(QStringLiteral("expire_settings"), mExpireConfigAction);
3377 connect(mExpireConfigAction, &QAction::triggered, mManageShowCollectionProperties, &ManageShowCollectionProperties::slotShowExpiryProperties);
3381 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("bookmark-new")), i18n("Add Favorite Folder..."), this);
3382 actionCollection()->addAction(QStringLiteral("add_favorite_folder"), action);
3383 connect(action, &QAction::triggered, this, &KMMainWidget::slotAddFavoriteFolder);
3387 mServerSideSubscription = new QAction(QIcon::fromTheme(QStringLiteral("folder-bookmarks")), i18n("Serverside Subscription..."), this);
3388 actionCollection()->addAction(QStringLiteral("serverside_subscription"), mServerSideSubscription);
3389 connect(mServerSideSubscription, &QAction::triggered, this, &KMMainWidget::slotServerSideSubscription);
3393 mApplyFiltersOnFolder = new QAction(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("Appl&y All Filters On Folder"), this);
3394 actionCollection()->addAction(QStringLiteral("apply_filters_on_folder"), mApplyFiltersOnFolder);
3395 connect(mApplyFiltersOnFolder, &QAction::triggered,
3396 this, &KMMainWidget::slotApplyFiltersOnFolder);
3401 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("kmail")), i18n("&Export KMail Data..."), this);
3402 actionCollection()->addAction(QStringLiteral("kmail_export_data"), action);
3403 connect(action, &QAction::triggered, mLaunchExternalComponent, &KMLaunchExternalComponent::slotExportData);
3407 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("contact-new")), i18n("New AddressBook Contact..."), this);
3408 actionCollection()->addAction(QStringLiteral("kmail_new_addressbook_contact"), action);
3409 connect(action, &QAction::triggered, this, &KMMainWidget::slotCreateAddressBookContact);
3413 actionCollection()->addAction(KStandardAction::Undo, QStringLiteral("kmail_undo"), this, SLOT(slotUndo()));
3415 menutimer = new QTimer(this);
3416 menutimer->setObjectName(QStringLiteral("menutimer"));
3417 menutimer->setSingleShot(true);
3418 connect(menutimer, &QTimer::timeout, this, &KMMainWidget::updateMessageActionsDelayed);
3419 connect(kmkernel->undoStack(),
3420 &KMail::UndoStack::undoStackChanged, this, &KMMainWidget::slotUpdateUndo);
3422 updateMessageActions();
3423 updateFolderMenu();
3424 mTagActionManager = new KMail::TagActionManager(this, actionCollection(), mMsgActions,
3425 mGUIClient);
3426 mFolderShortcutActionManager = new KMail::FolderShortcutActionManager(this, actionCollection());
3429 QAction *action = new QAction(i18n("Copy Message to Folder"), this);
3430 actionCollection()->addAction(QStringLiteral("copy_message_to_folder"), action);
3431 connect(action, &QAction::triggered,
3432 this, &KMMainWidget::slotCopySelectedMessagesToFolder);
3433 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_C));
3436 QAction *action = new QAction(i18n("Jump to Folder..."), this);
3437 actionCollection()->addAction(QStringLiteral("jump_to_folder"), action);
3438 connect(action, &QAction::triggered,
3439 this, &KMMainWidget::slotJumpToFolder);
3440 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_J));
3443 QAction *action = new QAction(i18n("Abort Current Operation"), this);
3444 actionCollection()->addAction(QStringLiteral("cancel"), action);
3445 connect(action, &QAction::triggered,
3446 ProgressManager::instance(), &KPIM::ProgressManager::slotAbortAll);
3447 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_Escape));
3450 QAction *action = new QAction(i18n("Focus on Next Folder"), this);
3451 actionCollection()->addAction(QStringLiteral("inc_current_folder"), action);
3452 connect(action, &QAction::triggered,
3453 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotFocusNextFolder);
3454 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Right));
3457 QAction *action = new QAction(i18n("Focus on Previous Folder"), this);
3458 actionCollection()->addAction(QStringLiteral("dec_current_folder"), action);
3459 connect(action, &QAction::triggered,
3460 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotFocusPrevFolder);
3461 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Left));
3464 QAction *action = new QAction(i18n("Select Folder with Focus"), this);
3465 actionCollection()->addAction(QStringLiteral("select_current_folder"), action);
3467 connect(action, &QAction::triggered,
3468 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotSelectFocusFolder);
3469 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Space));
3472 QAction *action = new QAction(i18n("Focus on First Folder"), this);
3473 actionCollection()->addAction(QStringLiteral("focus_first_folder"), action);
3474 connect(action, &QAction::triggered,
3475 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotFocusFirstFolder);
3476 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Home));
3479 QAction *action = new QAction(i18n("Focus on Last Folder"), this);
3480 actionCollection()->addAction(QStringLiteral("focus_last_folder"), action);
3481 connect(action, &QAction::triggered,
3482 mFolderTreeWidget->folderTreeView(), &FolderTreeView::slotFocusLastFolder);
3483 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_End));
3486 QAction *action = new QAction(i18n("Focus on Next Message"), this);
3487 actionCollection()->addAction(QStringLiteral("inc_current_message"), action);
3488 connect(action, &QAction::triggered,
3489 this, &KMMainWidget::slotFocusOnNextMessage);
3490 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Right));
3493 QAction *action = new QAction(i18n("Focus on Previous Message"), this);
3494 actionCollection()->addAction(QStringLiteral("dec_current_message"), action);
3495 connect(action, &QAction::triggered,
3496 this, &KMMainWidget::slotFocusOnPrevMessage);
3497 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Left));
3500 QAction *action = new QAction(i18n("Select First Message"), this);
3501 actionCollection()->addAction(QStringLiteral("select_first_message"), action);
3502 connect(action, &QAction::triggered,
3503 this, &KMMainWidget::slotSelectFirstMessage);
3504 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Home));
3507 QAction *action = new QAction(i18n("Select Last Message"), this);
3508 actionCollection()->addAction(QStringLiteral("select_last_message"), action);
3509 connect(action, &QAction::triggered,
3510 this, &KMMainWidget::slotSelectLastMessage);
3511 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_End));
3514 QAction *action = new QAction(i18n("Select Message with Focus"), this);
3515 actionCollection()->addAction(QStringLiteral("select_current_message"), action);
3516 connect(action, &QAction::triggered,
3517 this, &KMMainWidget::slotSelectFocusedMessage);
3518 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Space));
3522 mQuickSearchAction = new QAction(i18n("Set Focus to Quick Search"), this);
3523 //If change shortcut change Panel::setQuickSearchClickMessage(...) message
3524 actionCollection()->setDefaultShortcut(mQuickSearchAction, QKeySequence(Qt::ALT + Qt::Key_Q));
3525 actionCollection()->addAction(QStringLiteral("focus_to_quickseach"), mQuickSearchAction);
3526 connect(mQuickSearchAction, &QAction::triggered,
3527 this, &KMMainWidget::slotFocusQuickSearch);
3528 updateQuickSearchLineText();
3531 QAction *action = new QAction(i18n("Extend Selection to Previous Message"), this);
3532 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::Key_Left));
3533 actionCollection()->addAction(QStringLiteral("previous_message"), action);
3534 connect(action, &QAction::triggered,
3535 this, &KMMainWidget::slotExtendSelectionToPreviousMessage);
3538 QAction *action = new QAction(i18n("Extend Selection to Next Message"), this);
3539 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::Key_Right));
3540 actionCollection()->addAction(QStringLiteral("next_message"), action);
3541 connect(action, &QAction::triggered,
3542 this, &KMMainWidget::slotExtendSelectionToNextMessage);
3546 mMoveMsgToFolderAction = new QAction(i18n("Move Message to Folder"), this);
3547 actionCollection()->setDefaultShortcut(mMoveMsgToFolderAction, QKeySequence(Qt::Key_M));
3548 actionCollection()->addAction(QStringLiteral("move_message_to_folder"), mMoveMsgToFolderAction);
3549 connect(mMoveMsgToFolderAction, &QAction::triggered,
3550 this, &KMMainWidget::slotMoveSelectedMessageToFolder);
3553 mArchiveAction = new QAction(i18nc("@action", "Archive"), this);
3554 actionCollection()->addAction(QStringLiteral("archive_mails"), mArchiveAction);
3555 connect(mArchiveAction, &QAction::triggered, this, &KMMainWidget::slotArchiveMails);
3557 mLowBandwithAction = new KToggleAction(i18n("Low Bandwidth"), this);
3558 actionCollection()->addAction(QStringLiteral("low_bandwidth"), mLowBandwithAction);
3559 connect(mLowBandwithAction, &KToggleAction::triggered, this, &KMMainWidget::slotBandwidth);
3561 mMarkAllMessageAsReadAndInAllSubFolder = new QAction(i18n("Mark All Messages As Read in This Folder and All its Subfolder"), this);
3562 mMarkAllMessageAsReadAndInAllSubFolder->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-read")));
3563 actionCollection()->addAction(QStringLiteral("markallmessagereadcurentfolderandsubfolder"), mMarkAllMessageAsReadAndInAllSubFolder);
3564 connect(mMarkAllMessageAsReadAndInAllSubFolder, &KToggleAction::triggered, this, &KMMainWidget::slotMarkAllMessageAsReadInCurrentFolderAndSubfolder);
3568 void KMMainWidget::slotAddFavoriteFolder()
3570 if (!mFavoritesModel) {
3571 return;
3573 QPointer<MailCommon::FolderSelectionDialog> dialog(selectFromAllFoldersDialog());
3574 dialog->setWindowTitle(i18n("Add Favorite Folder"));
3575 if (dialog->exec() && dialog) {
3576 const Akonadi::Collection collection = dialog->selectedCollection();
3577 if (collection.isValid()) {
3578 mFavoritesModel->addCollection(collection);
3583 //-----------------------------------------------------------------------------
3584 void KMMainWidget::slotEditNotifications()
3586 KMail::KMKnotify notifyDlg(this);
3587 notifyDlg.exec();
3590 //-----------------------------------------------------------------------------
3591 void KMMainWidget::slotReadOn()
3593 if (!mMsgView) {
3594 return;
3596 if (!mMsgView->viewer()->atBottom()) {
3597 mMsgView->viewer()->slotJumpDown();
3598 return;
3600 slotSelectNextUnreadMessage();
3603 void KMMainWidget::slotNextUnreadFolder()
3605 if (!mFolderTreeWidget) {
3606 return;
3608 mGoToFirstUnreadMessageInSelectedFolder = true;
3609 mFolderTreeWidget->folderTreeView()->selectNextUnreadFolder();
3610 mGoToFirstUnreadMessageInSelectedFolder = false;
3613 void KMMainWidget::slotPrevUnreadFolder()
3615 if (!mFolderTreeWidget) {
3616 return;
3618 mGoToFirstUnreadMessageInSelectedFolder = true;
3619 mFolderTreeWidget->folderTreeView()->selectPrevUnreadFolder();
3620 mGoToFirstUnreadMessageInSelectedFolder = false;
3623 void KMMainWidget::slotExpandThread()
3625 mMessagePane->setCurrentThreadExpanded(true);
3628 void KMMainWidget::slotCollapseThread()
3630 mMessagePane->setCurrentThreadExpanded(false);
3633 void KMMainWidget::slotExpandAllThreads()
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(true);
3642 void KMMainWidget::slotCollapseAllThreads()
3644 // TODO: Make this asynchronous ? (if there is enough demand)
3645 #ifndef QT_NO_CURSOR
3646 KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
3647 #endif
3648 mMessagePane->setAllThreadsExpanded(false);
3651 //-----------------------------------------------------------------------------
3652 void KMMainWidget::updateMessageMenu()
3654 updateMessageActions();
3657 void KMMainWidget::startUpdateMessageActionsTimer()
3659 // FIXME: This delay effectively CAN make the actions to be in an incoherent state
3660 // Maybe we should mark actions as "dirty" here and check it in every action handler...
3661 updateMessageActions(true);
3663 menutimer->stop();
3664 menutimer->start(500);
3667 void KMMainWidget::updateMessageActions(bool fast)
3669 Akonadi::Item::List selectedItems;
3670 Akonadi::Item::List selectedVisibleItems;
3671 bool allSelectedBelongToSameThread = false;
3672 if (mCurrentFolder && mCurrentFolder->isValid() &&
3673 mMessagePane->getSelectionStats(selectedItems, selectedVisibleItems, &allSelectedBelongToSameThread)
3675 mMsgActions->setCurrentMessage(mMessagePane->currentItem(), selectedVisibleItems);
3676 } else {
3677 mMsgActions->setCurrentMessage(Akonadi::Item());
3680 if (!fast) {
3681 updateMessageActionsDelayed();
3686 void KMMainWidget::updateMessageActionsDelayed()
3688 int count;
3689 Akonadi::Item::List selectedItems;
3690 Akonadi::Item::List selectedVisibleItems;
3691 bool allSelectedBelongToSameThread = false;
3692 Akonadi::Item currentMessage;
3693 if (mCurrentFolder && mCurrentFolder->isValid() &&
3694 mMessagePane->getSelectionStats(selectedItems, selectedVisibleItems, &allSelectedBelongToSameThread)
3696 count = selectedItems.count();
3698 currentMessage = mMessagePane->currentItem();
3700 } else {
3701 count = 0;
3702 currentMessage = Akonadi::Item();
3705 mApplyFiltersOnFolder->setEnabled(mCurrentFolder && mCurrentFolder->isValid());
3708 // Here we have:
3710 // - A list of selected messages stored in selectedSernums.
3711 // The selected messages might contain some invisible ones as a selected
3712 // collapsed node "includes" all the children in the selection.
3713 // - A list of selected AND visible messages stored in selectedVisibleSernums.
3714 // This list does not contain children of selected and collapsed nodes.
3716 // Now, actions can operate on:
3717 // - Any set of messages
3718 // These are called "mass actions" and are enabled whenever we have a message selected.
3719 // In fact we should differentiate between actions that operate on visible selection
3720 // and those that operate on the selection as a whole (without considering visibility)...
3721 // - A single thread
3722 // These are called "thread actions" and are enabled whenever all the selected messages belong
3723 // to the same thread. If the selection doesn't cover the whole thread then the action
3724 // will act on the whole thread anyway (thus will silently extend the selection)
3725 // - A single message
3726 // And we have two sub-cases:
3727 // - The selection must contain exactly one message
3728 // These actions can't ignore the hidden messages and thus must be disabled if
3729 // the selection contains any.
3730 // - The selection must contain exactly one visible message
3731 // These actions will ignore the hidden message and thus can be enabled if
3732 // the selection contains any.
3735 bool readOnly = mCurrentFolder && mCurrentFolder->isValid() && (mCurrentFolder->rights() & Akonadi::Collection::ReadOnly);
3736 // can we apply strictly single message actions ? (this is false if the whole selection contains more than one message)
3737 bool single_actions = count == 1;
3738 // can we apply loosely single message actions ? (this is false if the VISIBLE selection contains more than one message)
3739 bool singleVisibleMessageSelected = selectedVisibleItems.count() == 1;
3740 // can we apply "mass" actions to the selection ? (this is actually always true if the selection is non-empty)
3741 bool mass_actions = count >= 1;
3742 // does the selection identify a single thread ?
3743 bool thread_actions = mass_actions && allSelectedBelongToSameThread && mMessagePane->isThreaded();
3744 // can we apply flags to the selected messages ?
3745 bool flags_available = KMailSettings::self()->allowLocalFlags() || !(mCurrentFolder && mCurrentFolder->isValid() ? readOnly : true);
3747 mThreadStatusMenu->setEnabled(thread_actions);
3748 // these need to be handled individually, the user might have them
3749 // in the toolbar
3750 mWatchThreadAction->setEnabled(thread_actions && flags_available);
3751 mIgnoreThreadAction->setEnabled(thread_actions && flags_available);
3752 mMarkThreadAsReadAction->setEnabled(thread_actions);
3753 mMarkThreadAsUnreadAction->setEnabled(thread_actions);
3754 mToggleThreadToActAction->setEnabled(thread_actions && flags_available);
3755 mToggleThreadImportantAction->setEnabled(thread_actions && flags_available);
3756 bool canDeleteMessages = mCurrentFolder && mCurrentFolder->isValid() && (mCurrentFolder->rights() & Akonadi::Collection::CanDeleteItem);
3758 mTrashThreadAction->setEnabled(thread_actions && canDeleteMessages);
3759 mDeleteThreadAction->setEnabled(thread_actions && canDeleteMessages);
3761 if (currentMessage.isValid()) {
3762 MessageStatus status;
3763 status.setStatusFromFlags(currentMessage.flags());
3764 mTagActionManager->updateActionStates(count, mMessagePane->currentItem());
3765 if (thread_actions) {
3766 mToggleThreadToActAction->setChecked(status.isToAct());
3767 mToggleThreadImportantAction->setChecked(status.isImportant());
3768 mWatchThreadAction->setChecked(status.isWatched());
3769 mIgnoreThreadAction->setChecked(status.isIgnored());
3773 mMoveActionMenu->setEnabled(mass_actions && canDeleteMessages);
3774 if (mMoveMsgToFolderAction) {
3775 mMoveMsgToFolderAction->setEnabled(mass_actions && canDeleteMessages);
3777 //mCopyActionMenu->setEnabled( mass_actions );
3779 mDeleteAction->setEnabled(mass_actions && canDeleteMessages);
3781 mExpireConfigAction->setEnabled(canDeleteMessages);
3783 if (mMsgView) {
3784 mMsgView->findInMessageAction()->setEnabled(mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3786 mMsgActions->forwardInlineAction()->setEnabled(mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3787 mMsgActions->forwardAttachedAction()->setEnabled(mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3788 mMsgActions->forwardMenu()->setEnabled(mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3790 mMsgActions->editAction()->setEnabled(single_actions);
3791 mUseAction->setEnabled(single_actions && CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3792 filterMenu()->setEnabled(single_actions);
3793 mMsgActions->redirectAction()->setEnabled(/*single_actions &&*/mass_actions && !CommonKernel->folderIsTemplates(mCurrentFolder->collection()));
3795 if (mMsgActions->customTemplatesMenu()) {
3796 mMsgActions->customTemplatesMenu()->forwardActionMenu()->setEnabled(mass_actions);
3797 mMsgActions->customTemplatesMenu()->replyActionMenu()->setEnabled(single_actions);
3798 mMsgActions->customTemplatesMenu()->replyAllActionMenu()->setEnabled(single_actions);
3801 // "Print" will act on the current message: it will ignore any hidden selection
3802 mMsgActions->printAction()->setEnabled(singleVisibleMessageSelected);
3803 // "Print preview" will act on the current message: it will ignore any hidden selection
3804 QAction *printPreviewAction = mMsgActions->printPreviewAction();
3805 if (printPreviewAction) {
3806 printPreviewAction->setEnabled(singleVisibleMessageSelected);
3809 // "View Source" will act on the current message: it will ignore any hidden selection
3810 if (mMsgView) {
3811 mMsgView->viewSourceAction()->setEnabled(singleVisibleMessageSelected);
3813 MessageStatus status;
3814 status.setStatusFromFlags(currentMessage.flags());
3816 QList< QAction *> actionList;
3817 bool statusSendAgain = single_actions && ((currentMessage.isValid() && status.isSent()) || (currentMessage.isValid() && CommonKernel->folderIsSentMailFolder(mCurrentFolder->collection())));
3818 if (statusSendAgain) {
3819 actionList << mSendAgainAction;
3820 } else if (single_actions) {
3821 actionList << messageActions()->editAction();
3823 actionList << mSaveAttachmentsAction;
3824 if (mCurrentFolder && FolderArchive::FolderArchiveUtil::resourceSupportArchiving(mCurrentFolder->collection().resource())) {
3825 actionList << mArchiveAction;
3827 mGUIClient->unplugActionList(QStringLiteral("messagelist_actionlist"));
3828 mGUIClient->plugActionList(QStringLiteral("messagelist_actionlist"), actionList);
3829 mSendAgainAction->setEnabled(statusSendAgain);
3831 mSaveAsAction->setEnabled(mass_actions);
3833 if ((mCurrentFolder && mCurrentFolder->isValid())) {
3834 updateMoveAction(mCurrentFolder->statistics());
3835 } else {
3836 updateMoveAction(false, false);
3839 const qint64 nbMsgOutboxCollection = MailCommon::Util::updatedCollection(CommonKernel->outboxCollectionFolder()).statistics().count();
3841 mSendQueued->setEnabled(nbMsgOutboxCollection > 0);
3842 mSendActionMenu->setEnabled(nbMsgOutboxCollection > 0);
3844 const bool newPostToMailingList = mCurrentFolder && mCurrentFolder->isMailingListEnabled();
3845 mMessageNewList->setEnabled(newPostToMailingList);
3847 slotUpdateOnlineStatus(static_cast<GlobalSettingsBase::EnumNetworkState::type>(KMailSettings::self()->networkState()));
3848 if (action(QStringLiteral("kmail_undo"))) {
3849 action(QStringLiteral("kmail_undo"))->setEnabled(kmkernel->undoStack()->size() > 0);
3852 // Enable / disable all filters.
3853 foreach (QAction *filterAction, mFilterMenuActions) {
3854 filterAction->setEnabled(count > 0);
3857 mApplyAllFiltersAction->setEnabled(count);
3858 mApplyFilterActionsMenu->setEnabled(count);
3861 void KMMainWidget::slotAkonadiStandardActionUpdated()
3863 bool multiFolder = false;
3864 if (mFolderTreeWidget) {
3865 multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3867 if (mCollectionProperties) {
3868 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
3869 const Akonadi::AgentInstance instance =
3870 Akonadi::AgentManager::self()->instance(mCurrentFolder->collection().resource());
3872 mCollectionProperties->setEnabled(!multiFolder &&
3873 !mCurrentFolder->isStructural() &&
3874 (instance.status() != Akonadi::AgentInstance::Broken));
3875 } else {
3876 mCollectionProperties->setEnabled(false);
3878 QList< QAction * > collectionProperties;
3879 if (mCollectionProperties->isEnabled()) {
3880 collectionProperties << mCollectionProperties;
3882 mGUIClient->unplugActionList(QStringLiteral("akonadi_collection_collectionproperties_actionlist"));
3883 mGUIClient->plugActionList(QStringLiteral("akonadi_collection_collectionproperties_actionlist"), collectionProperties);
3887 const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural();
3889 if (mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::DeleteCollections)) {
3891 mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::DeleteCollections)->setEnabled(mCurrentFolder
3892 && !multiFolder
3893 && (mCurrentFolder->collection().rights() & Collection::CanDeleteCollection)
3894 && !mCurrentFolder->isSystemFolder()
3895 && folderWithContent);
3898 if (mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)) {
3899 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)->setEnabled(folderWithContent
3900 && (mCurrentFolder->count() > 0)
3901 && mCurrentFolder->canDeleteMessages()
3902 && !multiFolder);
3903 mAkonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MoveAllToTrash)->setText((mCurrentFolder && CommonKernel->folderIsTrash(mCurrentFolder->collection())) ? i18n("E&mpty Trash") : i18n("&Move All Messages to Trash"));
3906 QList< QAction * > addToFavorite;
3907 QAction *actionAddToFavoriteCollections = akonadiStandardAction(Akonadi::StandardActionManager::AddToFavoriteCollections);
3908 if (actionAddToFavoriteCollections) {
3909 if (mEnableFavoriteFolderView && actionAddToFavoriteCollections->isEnabled()) {
3910 addToFavorite << actionAddToFavoriteCollections;
3912 mGUIClient->unplugActionList(QStringLiteral("akonadi_collection_add_to_favorites_actionlist"));
3913 mGUIClient->plugActionList(QStringLiteral("akonadi_collection_add_to_favorites_actionlist"), addToFavorite);
3916 QList< QAction * > syncActionList;
3917 QAction *actionSync = akonadiStandardAction(Akonadi::StandardActionManager::SynchronizeCollections);
3918 if (actionSync && actionSync->isEnabled()) {
3919 syncActionList << actionSync;
3921 actionSync = akonadiStandardAction(Akonadi::StandardActionManager::SynchronizeCollectionsRecursive);
3922 if (actionSync && actionSync->isEnabled()) {
3923 syncActionList << actionSync;
3925 mGUIClient->unplugActionList(QStringLiteral("akonadi_collection_sync_actionlist"));
3926 mGUIClient->plugActionList(QStringLiteral("akonadi_collection_sync_actionlist"), syncActionList);
3928 QList< QAction * > actionList;
3930 QAction *action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CreateCollection);
3931 if (action && action->isEnabled()) {
3932 actionList << action;
3935 action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::MoveCollectionToMenu);
3936 if (action && action->isEnabled()) {
3937 actionList << action;
3940 action = mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::CopyCollectionToMenu);
3941 if (action && action->isEnabled()) {
3942 actionList << action;
3944 mGUIClient->unplugActionList(QStringLiteral("akonadi_collection_move_copy_menu_actionlist"));
3945 mGUIClient->plugActionList(QStringLiteral("akonadi_collection_move_copy_menu_actionlist"), actionList);
3949 void KMMainWidget::updateHtmlMenuEntry()
3951 if (mDisplayMessageFormatMenu && mPreferHtmlLoadExtAction) {
3952 bool multiFolder = false;
3953 if (mFolderTreeWidget) {
3954 multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3956 // the visual ones only make sense if we are showing a message list
3957 const bool enabledAction = (mFolderTreeWidget &&
3958 mFolderTreeWidget->folderTreeView()->currentFolder().isValid() &&
3959 !multiFolder);
3961 mDisplayMessageFormatMenu->setEnabled(enabledAction);
3962 const bool isEnabled = (mFolderTreeWidget &&
3963 mFolderTreeWidget->folderTreeView()->currentFolder().isValid() &&
3964 !multiFolder);
3965 const bool useHtml = (mFolderDisplayFormatPreference == MessageViewer::Viewer::Html || (mHtmlGlobalSetting && mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting));
3966 mPreferHtmlLoadExtAction->setEnabled(isEnabled && useHtml);
3968 mDisplayMessageFormatMenu->setDisplayMessageFormat(mFolderDisplayFormatPreference);
3970 mPreferHtmlLoadExtAction->setChecked(!multiFolder && (mHtmlLoadExtGlobalSetting ? !mFolderHtmlLoadExtPreference : mFolderHtmlLoadExtPreference));
3974 //-----------------------------------------------------------------------------
3975 void KMMainWidget::updateFolderMenu()
3977 if (!CommonKernel->outboxCollectionFolder().isValid()) {
3978 QTimer::singleShot(1000, this, &KMMainWidget::updateFolderMenu);
3979 return;
3982 const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural();
3983 bool multiFolder = false;
3984 if (mFolderTreeWidget) {
3985 multiFolder = mFolderTreeWidget->selectedCollections().count() > 1;
3987 mFolderMailingListPropertiesAction->setEnabled(folderWithContent &&
3988 !multiFolder &&
3989 !mCurrentFolder->isSystemFolder());
3991 QList< QAction * > actionlist;
3992 if (mCurrentFolder && mCurrentFolder->collection().id() == CommonKernel->outboxCollectionFolder().id() && (mCurrentFolder->collection()).statistics().count() > 0) {
3993 qCDebug(KMAIL_LOG) << "Enabling send queued";
3994 mSendQueued->setEnabled(true);
3995 actionlist << mSendQueued;
3997 // if ( mCurrentFolder && mCurrentFolder->collection().id() != CommonKernel->trashCollectionFolder().id() ) {
3998 // actionlist << mTrashAction;
3999 // }
4000 mGUIClient->unplugActionList(QStringLiteral("outbox_folder_actionlist"));
4001 mGUIClient->plugActionList(QStringLiteral("outbox_folder_actionlist"), actionlist);
4002 actionlist.clear();
4004 const bool isASearchFolder = mCurrentFolder && mCurrentFolder->collection().resource() == QLatin1String("akonadi_search_resource");
4005 if (isASearchFolder) {
4006 mAkonadiStandardActionManager->action(Akonadi::StandardActionManager::DeleteCollections)->setText(i18n("&Delete Search"));
4009 mArchiveFolderAction->setEnabled(mCurrentFolder && !multiFolder && folderWithContent);
4011 bool isInTrashFolder = (mCurrentFolder && CommonKernel->folderIsTrash(mCurrentFolder->collection()));
4012 QAction *moveToTrash = akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash);
4013 akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash)->setText(isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "&Delete") : i18n("&Move to Trash"));
4014 akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash)->setIcon(isInTrashFolder ? QIcon::fromTheme(QStringLiteral("edit-delete")) : QIcon::fromTheme(QStringLiteral("user-trash")));
4015 //Use same text as in Text property. Change it in kf5
4016 moveToTrash->setToolTip(isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "&Delete") : i18n("&Move to Trash"));
4018 mTrashThreadAction->setIcon(isInTrashFolder ? QIcon::fromTheme(QStringLiteral("edit-delete")) : QIcon::fromTheme(QStringLiteral("user-trash")));
4019 mTrashThreadAction->setText(isInTrashFolder ? i18n("Delete T&hread") : i18n("M&ove Thread to Trash"));
4021 mSearchMessages->setText((mCurrentFolder && mCurrentFolder->collection().resource() == QLatin1String("akonadi_search_resource")) ? i18n("Edit Search...") : i18n("&Find Messages..."));
4023 mExpireConfigAction->setEnabled(mCurrentFolder &&
4024 !mCurrentFolder->isStructural() &&
4025 !multiFolder &&
4026 mCurrentFolder->canDeleteMessages() &&
4027 folderWithContent &&
4028 !MailCommon::Util::isVirtualCollection(mCurrentFolder->collection()));
4030 updateHtmlMenuEntry();
4032 mShowFolderShortcutDialogAction->setEnabled(!multiFolder && folderWithContent);
4034 actionlist << akonadiStandardAction(Akonadi::StandardActionManager::ManageLocalSubscriptions);
4035 bool imapFolderIsOnline = false;
4036 if (mCurrentFolder && PimCommon::Util::isImapFolder(mCurrentFolder->collection(), imapFolderIsOnline)) {
4037 if (imapFolderIsOnline) {
4038 actionlist << mServerSideSubscription;
4042 mGUIClient->unplugActionList(QStringLiteral("collectionview_actionlist"));
4043 mGUIClient->plugActionList(QStringLiteral("collectionview_actionlist"), actionlist);
4047 //-----------------------------------------------------------------------------
4048 void KMMainWidget::slotIntro()
4050 if (!mMsgView) {
4051 return;
4054 mMsgView->clear(true);
4056 // hide widgets that are in the way:
4057 if (mMessagePane && mLongFolderList) {
4058 mMessagePane->hide();
4060 mMsgView->displayAboutPage();
4062 mCurrentFolder.clear();
4065 void KMMainWidget::slotShowStartupFolder()
4067 connect(MailCommon::FilterManager::instance(), &FilterManager::filtersChanged,
4068 this, &KMMainWidget::initializeFilterActions);
4069 // Plug various action lists. This can't be done in the constructor, as that is called before
4070 // the main window or Kontact calls createGUI().
4071 // This function however is called with a single shot timer.
4072 checkAkonadiServerManagerState();
4073 mFolderShortcutActionManager->createActions();
4074 mTagActionManager->createActions();
4075 messageActions()->setupForwardingActionsList(mGUIClient);
4077 QString newFeaturesMD5 = KMReaderWin::newFeaturesMD5();
4078 if (kmkernel->firstStart() ||
4079 KMailSettings::self()->previousNewFeaturesMD5() != newFeaturesMD5) {
4080 KMailSettings::self()->setPreviousNewFeaturesMD5(newFeaturesMD5);
4081 slotIntro();
4082 return;
4086 void KMMainWidget::checkAkonadiServerManagerState()
4088 Akonadi::ServerManager::State state = Akonadi::ServerManager::self()->state();
4089 if (state == Akonadi::ServerManager::Running) {
4090 initializeFilterActions();
4091 } else {
4092 connect(Akonadi::ServerManager::self(), &ServerManager::stateChanged,
4093 this, &KMMainWidget::slotServerStateChanged);
4097 void KMMainWidget::slotServerStateChanged(Akonadi::ServerManager::State state)
4099 if (state == Akonadi::ServerManager::Running) {
4100 initializeFilterActions();
4101 disconnect(Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)));
4105 QList<KActionCollection *> KMMainWidget::actionCollections() const
4107 return QList<KActionCollection *>() << actionCollection();
4110 //-----------------------------------------------------------------------------
4111 void KMMainWidget::slotUpdateUndo()
4113 if (actionCollection()->action(QStringLiteral("kmail_undo"))) {
4114 QAction *act = actionCollection()->action(QStringLiteral("kmail_undo"));
4115 act->setEnabled(!kmkernel->undoStack()->isEmpty());
4116 const QString infoStr = kmkernel->undoStack()->undoInfo();
4117 if (infoStr.isEmpty()) {
4118 act->setText(i18n("&Undo"));
4119 } else {
4120 act->setText(i18n("&Undo: \"%1\"", kmkernel->undoStack()->undoInfo()));
4125 //-----------------------------------------------------------------------------
4126 void KMMainWidget::clearFilterActions()
4128 if (!mFilterTBarActions.isEmpty())
4129 if (mGUIClient->factory()) {
4130 mGUIClient->unplugActionList(QStringLiteral("toolbar_filter_actions"));
4133 if (!mFilterMenuActions.isEmpty())
4134 if (mGUIClient->factory()) {
4135 mGUIClient->unplugActionList(QStringLiteral("menu_filter_actions"));
4138 foreach (QAction *a, mFilterMenuActions) {
4139 actionCollection()->removeAction(a);
4142 mApplyFilterActionsMenu->menu()->clear();
4143 mFilterTBarActions.clear();
4144 mFilterMenuActions.clear();
4146 qDeleteAll(mFilterCommands);
4147 mFilterCommands.clear();
4150 //-----------------------------------------------------------------------------
4151 void KMMainWidget::initializeFilterActions()
4153 clearFilterActions();
4154 mApplyFilterActionsMenu->menu()->addAction(mApplyAllFiltersAction);
4155 bool addedSeparator = false;
4157 foreach (MailFilter *filter, MailCommon::FilterManager::instance()->filters()) {
4158 if (!filter->isEmpty() && filter->configureShortcut() && filter->isEnabled()) {
4159 QString filterName = QStringLiteral("Filter %1").arg(filter->name());
4160 QString normalizedName = filterName.replace(QLatin1Char(' '), QLatin1Char('_'));
4161 if (action(normalizedName)) {
4162 continue;
4164 KMMetaFilterActionCommand *filterCommand = new KMMetaFilterActionCommand(filter->identifier(), this);
4165 mFilterCommands.append(filterCommand);
4166 QString displayText = i18n("Filter %1", filter->name());
4167 QString icon = filter->icon();
4168 if (icon.isEmpty()) {
4169 icon = QStringLiteral("system-run");
4171 QAction *filterAction = new QAction(QIcon::fromTheme(icon), displayText, actionCollection());
4172 filterAction->setIconText(filter->toolbarName());
4174 // The shortcut configuration is done in the filter dialog.
4175 // The shortcut set in the shortcut dialog would not be saved back to
4176 // the filter settings correctly.
4177 actionCollection()->setShortcutsConfigurable(filterAction, false);
4178 actionCollection()->addAction(normalizedName,
4179 filterAction);
4180 connect(filterAction, &QAction::triggered,
4181 filterCommand, &KMMetaFilterActionCommand::start);
4182 actionCollection()->setDefaultShortcut(filterAction, filter->shortcut());
4183 if (!addedSeparator) {
4184 QAction *a = mApplyFilterActionsMenu->menu()->addSeparator();
4185 mFilterMenuActions.append(a);
4186 addedSeparator = true;
4188 mApplyFilterActionsMenu->menu()->addAction(filterAction);
4189 mFilterMenuActions.append(filterAction);
4190 if (filter->configureToolbar()) {
4191 mFilterTBarActions.append(filterAction);
4195 if (!mFilterMenuActions.isEmpty() && mGUIClient->factory()) {
4196 mGUIClient->plugActionList(QStringLiteral("menu_filter_actions"), mFilterMenuActions);
4198 if (!mFilterTBarActions.isEmpty() && mGUIClient->factory()) {
4199 mFilterTBarActions.prepend(mToolbarActionSeparator);
4200 mGUIClient->plugActionList(QStringLiteral("toolbar_filter_actions"), mFilterTBarActions);
4203 // Our filters have changed, now enable/disable them
4204 updateMessageActions();
4207 void KMMainWidget::updateFileMenu()
4209 const bool isEmpty = MailCommon::Util::agentInstances().isEmpty();
4210 actionCollection()->action(QStringLiteral("check_mail"))->setEnabled(!isEmpty);
4211 actionCollection()->action(QStringLiteral("check_mail_in"))->setEnabled(!isEmpty);
4214 //-----------------------------------------------------------------------------
4215 const KMMainWidget::PtrList *KMMainWidget::mainWidgetList()
4217 // better safe than sorry; check whether the global static has already been destroyed
4218 if (theMainWidgetList.isDestroyed()) {
4219 return Q_NULLPTR;
4221 return theMainWidgetList;
4224 QSharedPointer<FolderCollection> KMMainWidget::currentFolder() const
4226 return mCurrentFolder;
4229 //-----------------------------------------------------------------------------
4230 QString KMMainWidget::overrideEncoding() const
4232 if (mMsgView) {
4233 return mMsgView->overrideEncoding();
4234 } else {
4235 return MessageCore::MessageCoreSettings::self()->overrideCharacterEncoding();
4239 void KMMainWidget::showEvent(QShowEvent *event)
4241 QWidget::showEvent(event);
4242 mWasEverShown = true;
4245 void KMMainWidget::slotRequestFullSearchFromQuickSearch()
4247 // First, open the search window. If we are currently on a search folder,
4248 // the search associated with that will be loaded.
4249 if (!slotSearch()) {
4250 return;
4253 assert(mSearchWin);
4255 // Now we look at the current state of the quick search, and if there's
4256 // something in there, we add the criteria to the existing search for
4257 // the search folder, if applicable, or make a new one from it.
4258 SearchPattern pattern;
4259 const QString searchString = mMessagePane->currentFilterSearchString();
4260 if (!searchString.isEmpty()) {
4261 MessageList::Core::QuickSearchLine::SearchOptions options = mMessagePane->currentOptions();
4262 QByteArray searchStringVal;
4263 if (options & MessageList::Core::QuickSearchLine::SearchEveryWhere) {
4264 searchStringVal = "<message>";
4265 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstSubject) {
4266 searchStringVal = "subject";
4267 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstBody) {
4268 searchStringVal = "<body>";
4269 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstFrom) {
4270 searchStringVal = "from";
4271 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstBcc) {
4272 searchStringVal = "bcc";
4273 } else if (options & MessageList::Core::QuickSearchLine::SearchAgainstTo) {
4274 searchStringVal = "to";
4275 } else {
4276 searchStringVal = "<message>";
4278 pattern.append(SearchRule::createInstance(searchStringVal, SearchRule::FuncContains, searchString));
4279 QList<MessageStatus> statusList = mMessagePane->currentFilterStatus();
4280 Q_FOREACH (MessageStatus status, statusList) {
4281 if (status.hasAttachment()) {
4282 pattern.append(SearchRule::createInstance(searchStringVal, SearchRule::FuncHasAttachment, searchString));
4283 status.setHasAttachment(false);
4285 if (!status.isOfUnknownStatus()) {
4286 pattern.append(SearchRule::Ptr(new SearchRuleStatus(status)));
4290 if (!pattern.isEmpty()) {
4291 mSearchWin->addRulesToSearchPattern(pattern);
4295 void KMMainWidget::updateVacationScriptStatus(bool active, const QString &serverName)
4297 mVacationScriptIndicator->setVacationScriptActive(active, serverName);
4298 mVacationIndicatorActive = mVacationScriptIndicator->hasVacationScriptActive();
4301 QWidget *KMMainWidget::vacationScriptIndicator() const
4303 return mVacationScriptIndicator;
4306 void KMMainWidget::updateVacationScriptStatus()
4308 updateVacationScriptStatus(mVacationIndicatorActive);
4311 KMail::TagActionManager *KMMainWidget::tagActionManager() const
4313 return mTagActionManager;
4316 KMail::FolderShortcutActionManager *KMMainWidget::folderShortcutActionManager() const
4318 return mFolderShortcutActionManager;
4321 void KMMainWidget::slotMessageSelected(const Akonadi::Item &item)
4323 delete mShowBusySplashTimer;
4324 mShowBusySplashTimer = Q_NULLPTR;
4325 if (mMsgView) {
4326 // The current selection was cleared, so we'll remove the previously
4327 // selected message from the preview pane
4328 if (!item.isValid()) {
4329 mMsgView->clear();
4330 } else {
4331 mShowBusySplashTimer = new QTimer(this);
4332 mShowBusySplashTimer->setSingleShot(true);
4333 connect(mShowBusySplashTimer, &QTimer::timeout, this, &KMMainWidget::slotShowBusySplash);
4334 mShowBusySplashTimer->start(1000);
4336 Akonadi::ItemFetchJob *itemFetchJob = MessageViewer::Viewer::createFetchJob(item);
4337 if (mCurrentFolder) {
4338 const QString resource = mCurrentFolder->collection().resource();
4339 itemFetchJob->setProperty("_resource", QVariant::fromValue(resource));
4340 connect(itemFetchJob, &ItemFetchJob::itemsReceived,
4341 this, &KMMainWidget::itemsReceived);
4342 connect(itemFetchJob, &Akonadi::ItemFetchJob::result, this, &KMMainWidget::itemsFetchDone);
4348 void KMMainWidget::itemsReceived(const Akonadi::Item::List &list)
4350 Q_ASSERT(list.size() == 1);
4351 delete mShowBusySplashTimer;
4352 mShowBusySplashTimer = Q_NULLPTR;
4354 if (!mMsgView) {
4355 return;
4358 Item item = list.first();
4360 if (mMessagePane) {
4361 mMessagePane->show();
4363 if (mMessagePane->currentItem() != item) {
4364 // The user has selected another email already, so don't render this one.
4365 // Mark it as read, though, if the user settings say so.
4366 if (MessageViewer::MessageViewerSettings::self()->delayedMarkAsRead() &&
4367 MessageViewer::MessageViewerSettings::self()->delayedMarkTime() == 0) {
4368 item.setFlag(Akonadi::MessageFlags::Seen);
4369 Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob(item, this);
4370 modifyJob->disableRevisionCheck();
4371 modifyJob->setIgnorePayload(true);
4373 return;
4377 mMsgView->setMessage(item);
4378 // reset HTML Q_DECL_OVERRIDE to the folder setting
4379 mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
4380 mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference);
4381 mMsgView->setDecryptMessageOverwrite(false);
4382 mMsgActions->setCurrentMessage(item);
4385 void KMMainWidget::itemsFetchDone(KJob *job)
4387 delete mShowBusySplashTimer;
4388 mShowBusySplashTimer = Q_NULLPTR;
4389 if (job->error()) {
4390 // Unfortunately job->error() is Job::Unknown in many cases.
4391 // (see JobPrivate::handleResponse in akonadi/job.cpp)
4392 // So we show the "offline" page after checking the resource status.
4393 qCDebug(KMAIL_LOG) << job->error() << job->errorString();
4395 const QString resource = job->property("_resource").toString();
4396 const Akonadi::AgentInstance agentInstance = Akonadi::AgentManager::self()->instance(resource);
4397 if (!agentInstance.isOnline()) {
4398 // The resource is offline
4399 if (mMsgView) {
4400 mMsgView->viewer()->enableMessageDisplay();
4401 mMsgView->clear(true);
4403 mMessagePane->show();
4405 if (kmkernel->isOffline()) {
4406 showOfflinePage();
4407 } else {
4408 if (mMsgView) {
4409 showResourceOfflinePage();
4412 } else {
4413 // Some other error
4414 BroadcastStatus::instance()->setStatusMsg(job->errorString());
4419 QAction *KMMainWidget::akonadiStandardAction(Akonadi::StandardActionManager::Type type)
4421 return mAkonadiStandardActionManager->action(type);
4424 QAction *KMMainWidget::akonadiStandardAction(Akonadi::StandardMailActionManager::Type type)
4426 return mAkonadiStandardActionManager->action(type);
4429 void KMMainWidget::slotRemoveDuplicates()
4431 RemoveDuplicateMailJob *job = new RemoveDuplicateMailJob(mFolderTreeWidget->folderTreeView()->selectionModel(), this, this);
4432 job->start();
4435 void KMMainWidget::slotServerSideSubscription()
4437 if (!mCurrentFolder) {
4438 return;
4440 PimCommon::ManageServerSideSubscriptionJob *job = new PimCommon::ManageServerSideSubscriptionJob(this);
4441 job->setCurrentCollection(mCurrentFolder->collection());
4442 job->setParentWidget(this);
4443 job->start();
4446 void KMMainWidget::savePaneSelection()
4448 if (mMessagePane) {
4449 mMessagePane->saveCurrentSelection();
4453 void KMMainWidget::updatePaneTagComboBox()
4455 if (mMessagePane) {
4456 mMessagePane->updateTagComboBox();
4460 void KMMainWidget::slotCreateAddressBookContact()
4462 CreateNewContactJob *job = new CreateNewContactJob(this, this);
4463 job->start();
4466 void KMMainWidget::slotOpenRecentMsg(const QUrl &url)
4468 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand(this, url, overrideEncoding(), this);
4469 openCommand->start();
4472 void KMMainWidget::addRecentFile(const QUrl &mUrl)
4474 mOpenRecentAction->addUrl(mUrl);
4475 KConfigGroup grp = mConfig->group(QStringLiteral("Recent Files"));
4476 mOpenRecentAction->saveEntries(grp);
4477 grp.sync();
4480 void KMMainWidget::slotMoveMessageToTrash()
4482 if (messageView() && messageView()->viewer() && mCurrentFolder) {
4483 KMTrashMsgCommand *command = new KMTrashMsgCommand(mCurrentFolder->collection(), messageView()->viewer()->messageItem(), -1);
4484 command->start();
4488 void KMMainWidget::slotArchiveMails()
4490 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
4491 const Akonadi::Item::List selectedMessages = mMessagePane->selectionAsMessageItemList();
4492 KMKernel::self()->folderArchiveManager()->setArchiveItems(selectedMessages, mCurrentFolder->collection().resource());
4496 void KMMainWidget::updateQuickSearchLineText()
4498 //If change change shortcut
4499 mMessagePane->setQuickSearchClickMessage(i18nc("Show shortcut for focus quick search. Don't change it", "Search...<%1>", mQuickSearchAction->shortcut().toString()));
4502 void KMMainWidget::slotChangeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage format)
4504 if (format == MessageViewer::Viewer::Html) {
4505 const int result = KMessageBox::warningContinueCancel(this,
4506 // the warning text is taken from configuredialog.cpp:
4507 i18n("Use of HTML in mail will make you more vulnerable to "
4508 "\"spam\" and may increase the likelihood that your system will be "
4509 "compromised by other present and anticipated security exploits."),
4510 i18n("Security Warning"),
4511 KGuiItem(i18n("Use HTML")),
4512 KStandardGuiItem::cancel(),
4513 QStringLiteral("OverrideHtmlWarning"), Q_NULLPTR);
4514 if (result == KMessageBox::Cancel) {
4515 mDisplayMessageFormatMenu->setDisplayMessageFormat(MessageViewer::Viewer::Text);
4516 return;
4519 mFolderDisplayFormatPreference = format;
4521 //Update mPrefererHtmlLoadExtAction
4522 const bool useHtml = (mFolderDisplayFormatPreference == MessageViewer::Viewer::Html || (mHtmlGlobalSetting && mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting));
4523 mPreferHtmlLoadExtAction->setEnabled(useHtml);
4525 if (mMsgView) {
4526 mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
4527 mMsgView->update(true);
4531 void KMMainWidget::populateMessageListStatusFilterCombo()
4533 mMessagePane->populateStatusFilterCombo();
4536 void KMMainWidget::slotCollectionRemoved(const Akonadi::Collection &col)
4538 if (mFavoritesModel) {
4539 mFavoritesModel->removeCollection(col);
4543 void KMMainWidget::slotMarkAllMessageAsReadInCurrentFolderAndSubfolder()
4545 if (mCurrentFolder && mCurrentFolder->collection().isValid()) {
4546 MarkAllMessagesAsReadInFolderAndSubFolderJob *job = new MarkAllMessagesAsReadInFolderAndSubFolderJob(this);
4547 job->setTopLevelCollection(mCurrentFolder->collection());
4548 job->start();