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
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"
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"
52 #include <ksieveui/sievedebugdialog.h>
53 using KSieveUi::SieveDebugDialog
;
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"
81 #include "kdepim-version.h"
83 #include "messageviewer/messageviewersettings.h"
84 #include "messageviewer/viewer.h"
85 #include "messageviewer/attachmentstrategy.h"
87 #include "Libkdepim/KCursorSaver"
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>
149 #include <kwindowsystem.h>
150 #include <kmessagebox.h>
151 #include <kactionmenu.h>
153 #include <kacceleratormanager.h>
154 #include <kstandardshortcut.h>
155 #include <kcharsets.h>
156 #include "kmail_debug.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>
170 #include <ktreewidgetsearchline.h>
171 #include <KRecentFilesAction>
174 #include <QByteArray>
175 #include <QHeaderView>
178 #include <QVBoxLayout>
181 #include <QDBusConnection>
182 #include <QTextDocument>
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
) :
209 mMoveMsgToFolderAction(Q_NULLPTR
),
210 mCollectionProperties(Q_NULLPTR
),
211 mFavoriteCollectionsView(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;
238 mActionCollection
= actionCollection
;
239 mTopLayout
= new QVBoxLayout(this);
240 mTopLayout
->setMargin(0);
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);
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"));
328 mLaunchExternalComponent
->slotAccountWizard();
331 mLaunchExternalComponent
->slotAccountWizard();
334 // must be the last line of the constructor:
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();
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
));
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
);
379 //-----------------------------------------------------------------------------
380 //This method performs all cleanup that requires the kernel to exist.
381 void KMMainWidget::destruct()
389 disconnect(mFolderTreeWidget
->folderTreeView()->selectionModel(), &QItemSelectionModel::selectionChanged
, this, &KMMainWidget::updateFolderMenu
);
390 writeConfig(false); /* don't force kmkernel sync when close BUG: 289287 */
393 mCurrentFolder
.clear();
394 delete mMoveOrCopyToDialog
;
395 delete mSelectFromAllFoldersDialog
;
397 disconnect(kmkernel
->folderCollectionMonitor(), SIGNAL(itemAdded(Akonadi::Item
,Akonadi::Collection
)), this, Q_NULLPTR
);
398 disconnect(kmkernel
->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item
)), this, Q_NULLPTR
);
399 disconnect(kmkernel
->folderCollectionMonitor(), SIGNAL(itemMoved(Akonadi::Item
,Akonadi::Collection
,Akonadi::Collection
)), this, Q_NULLPTR
);
400 disconnect(kmkernel
->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection
,QSet
<QByteArray
>)), this, Q_NULLPTR
);
401 disconnect(kmkernel
->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id
,Akonadi::CollectionStatistics
)), this, Q_NULLPTR
);
406 void KMMainWidget::slotStartCheckMail()
408 if (mCheckMailTimer
.isActive()) {
409 mCheckMailTimer
.stop();
413 void KMMainWidget::slotEndCheckMail()
415 if (!mCheckMailTimer
.isActive()) {
416 mCheckMailTimer
.start();
420 void KMMainWidget::slotUpdateActionsAfterMailChecking()
422 const bool sendOnAll
=
423 KMailSettings::self()->sendOnCheck() == KMailSettings::EnumSendOnCheck::SendOnAllChecks
;
424 const bool sendOnManual
=
425 KMailSettings::self()->sendOnCheck() == KMailSettings::EnumSendOnCheck::SendOnManualChecks
;
426 if (!kmkernel
->isOffline() && (sendOnAll
|| sendOnManual
)) {
429 // update folder menus in case some mail got filtered to trash/current folder
430 // and we can enable "empty trash/move all to trash" action etc.
434 void KMMainWidget::slotCollectionFetched(int collectionId
)
436 // Called when a collection is fetched for the first time by the ETM.
437 // This is the right time to update the caption (which still says "Loading...")
438 // and to update the actions that depend on the number of mails in the folder.
439 if (mCurrentFolder
&& collectionId
== mCurrentFolder
->collection().id()) {
440 mCurrentFolder
->setCollection(MailCommon::Util::updatedCollection(mCurrentFolder
->collection()));
441 updateMessageActions();
444 // We call this for any collection, it could be one of our parents...
445 if (mCurrentFolder
) {
446 Q_EMIT
captionChangeRequest(MailCommon::Util::fullCollectionPath(mCurrentFolder
->collection()));
450 void KMMainWidget::slotFolderChanged(const Akonadi::Collection
&collection
)
452 folderSelected(collection
);
453 if (collection
.cachePolicy().syncOnDemand()) {
454 AgentManager::self()->synchronizeCollection(collection
, false);
456 mMsgActions
->setCurrentMessage(Akonadi::Item());
457 Q_EMIT
captionChangeRequest(MailCommon::Util::fullCollectionPath(collection
));
460 void KMMainWidget::folderSelected(const Akonadi::Collection
&col
)
462 // This is connected to the MainFolderView signal triggering when a folder is selected
464 if (mGoToFirstUnreadMessageInSelectedFolder
) {
465 // the default action has been overridden from outside
466 mPreSelectionMode
= MessageList::Core::PreSelectFirstUnreadCentered
;
468 // use the default action
469 switch (KMailSettings::self()->actionEnterFolder()) {
470 case KMailSettings::EnumActionEnterFolder::SelectFirstUnread
:
471 mPreSelectionMode
= MessageList::Core::PreSelectFirstUnreadCentered
;
473 case KMailSettings::EnumActionEnterFolder::SelectLastSelected
:
474 mPreSelectionMode
= MessageList::Core::PreSelectLastSelected
;
476 case KMailSettings::EnumActionEnterFolder::SelectNewest
:
477 mPreSelectionMode
= MessageList::Core::PreSelectNewestCentered
;
479 case KMailSettings::EnumActionEnterFolder::SelectOldest
:
480 mPreSelectionMode
= MessageList::Core::PreSelectOldestCentered
;
483 mPreSelectionMode
= MessageList::Core::PreSelectNone
;
488 mGoToFirstUnreadMessageInSelectedFolder
= false;
490 KPIM::KCursorSaver
busy(KPIM::KBusyPtr::busy());
494 mMsgView
->clear(true);
496 const bool newFolder
= mCurrentFolder
&& (mCurrentFolder
->collection() != col
);
498 // Delete any pending timer, if needed it will be recreated below
499 delete mShowBusySplashTimer
;
500 mShowBusySplashTimer
= Q_NULLPTR
;
502 // We're changing folder: write configuration for the old one
506 mCurrentFolder
= FolderCollection::forCollection(col
);
510 mMsgView
->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference
);
511 mMsgView
->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference
);
514 if (!mCurrentFolder
->isValid() && (mMessagePane
->count() < 2)) {
518 updateMessageActions();
521 // The message pane uses the selection model of the folder view to load the correct aggregation model and theme
522 // settings. At this point the selection model hasn't been updated yet to the user's new choice, so it would load
523 // the old folder settings instead.
524 QTimer::singleShot(0, this, &KMMainWidget::slotShowSelectedFolderInPane
);
527 void KMMainWidget::slotShowSelectedFolderInPane()
529 if (mCurrentFolder
&& mCurrentFolder
->collection().isValid()) {
530 mMessagePane
->setCurrentFolder(mCurrentFolder
->collection(), false, mPreSelectionMode
);
534 void KMMainWidget::clearViewer()
537 mMsgView
->clear(true);
538 mMsgView
->displayAboutPage();
542 //-----------------------------------------------------------------------------
543 void KMMainWidget::readPreConfig()
545 mLongFolderList
= KMailSettings::self()->folderList() == KMailSettings::EnumFolderList::longlist
;
546 mReaderWindowActive
= KMailSettings::self()->readerWindowMode() != KMailSettings::EnumReaderWindowMode::hide
;
547 mReaderWindowBelow
= KMailSettings::self()->readerWindowMode() == KMailSettings::EnumReaderWindowMode::below
;
549 mHtmlGlobalSetting
= MessageViewer::MessageViewerSettings::self()->htmlMail();
550 mHtmlLoadExtGlobalSetting
= MessageViewer::MessageViewerSettings::self()->htmlLoadExternal();
552 mEnableFavoriteFolderView
= (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() != MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode
);
553 mEnableFolderQuickSearch
= KMailSettings::self()->enableFolderQuickSearch();
555 updateHtmlMenuEntry();
557 mMsgView
->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference
);
558 mMsgView
->update(true);
562 //-----------------------------------------------------------------------------
563 void KMMainWidget::readFolderConfig()
565 if (!mCurrentFolder
|| !mCurrentFolder
->isValid()) {
568 KSharedConfig::Ptr config
= KMKernel::self()->config();
569 KConfigGroup
group(config
, MailCommon::FolderCollection::configGroupName(mCurrentFolder
->collection()));
570 if (group
.hasKey("htmlMailOverride")) {
571 const bool useHtml
= group
.readEntry("htmlMailOverride", false);
572 mFolderDisplayFormatPreference
= useHtml
? MessageViewer::Viewer::Html
: MessageViewer::Viewer::Text
;
573 group
.deleteEntry("htmlMailOverride");
576 mFolderDisplayFormatPreference
= static_cast<MessageViewer::Viewer::DisplayFormatMessage
>(group
.readEntry("displayFormatOverride", static_cast<int>(MessageViewer::Viewer::UseGlobalSetting
)));
578 mFolderHtmlLoadExtPreference
=
579 group
.readEntry("htmlLoadExternalOverride", false);
582 //-----------------------------------------------------------------------------
583 void KMMainWidget::writeFolderConfig()
585 if (mCurrentFolder
&& mCurrentFolder
->isValid()) {
586 KSharedConfig::Ptr config
= KMKernel::self()->config();
587 KConfigGroup
group(config
, MailCommon::FolderCollection::configGroupName(mCurrentFolder
->collection()));
588 group
.writeEntry("htmlLoadExternalOverride", mFolderHtmlLoadExtPreference
);
589 if (mFolderDisplayFormatPreference
== MessageViewer::Viewer::UseGlobalSetting
) {
590 group
.deleteEntry("displayFormatOverride");
592 group
.writeEntry("displayFormatOverride", static_cast<int>(mFolderDisplayFormatPreference
));
597 //-----------------------------------------------------------------------------
598 void KMMainWidget::layoutSplitters()
600 // This function can only be called when the old splitters are already deleted
601 Q_ASSERT(!mSplitter1
);
602 Q_ASSERT(!mSplitter2
);
604 // For some reason, this is necessary here so that the copy action still
605 // works after changing the folder layout.
607 disconnect(mMsgView
->copyAction(), &QAction::triggered
,
608 mMsgView
, &KMReaderWin::slotCopySelectedText
);
610 // If long folder list is enabled, the splitters are:
611 // Splitter 1: FolderView vs (HeaderAndSearch vs MessageViewer)
612 // Splitter 2: HeaderAndSearch vs MessageViewer
614 // If long folder list is disabled, the splitters are:
615 // Splitter 1: (FolderView vs HeaderAndSearch) vs MessageViewer
616 // Splitter 2: FolderView vs HeaderAndSearch
618 // The folder view is both the folder tree and the favorite folder view, if
621 const bool readerWindowAtSide
= !mReaderWindowBelow
&& mReaderWindowActive
;
622 const bool readerWindowBelow
= mReaderWindowBelow
&& mReaderWindowActive
;
624 mSplitter1
= new QSplitter(this);
625 mSplitter2
= new QSplitter(mSplitter1
);
627 QWidget
*folderTreeWidget
= mSearchAndTree
;
628 if (mFavoriteCollectionsView
) {
629 mFolderViewSplitter
= new QSplitter(Qt::Vertical
);
630 //mFolderViewSplitter->setChildrenCollapsible( false );
631 mFolderViewSplitter
->addWidget(mFavoriteCollectionsView
);
632 mFavoriteCollectionsView
->setParent(mFolderViewSplitter
);
633 mFolderViewSplitter
->addWidget(mSearchAndTree
);
634 folderTreeWidget
= mFolderViewSplitter
;
637 if (mLongFolderList
) {
640 mSplitter1
->setOrientation(Qt::Horizontal
);
641 mSplitter1
->addWidget(folderTreeWidget
);
643 // and the rest to the right
644 mSplitter1
->addWidget(mSplitter2
);
646 // add the message list to the right or below
647 if (readerWindowAtSide
) {
648 mSplitter2
->setOrientation(Qt::Horizontal
);
650 mSplitter2
->setOrientation(Qt::Vertical
);
652 mSplitter2
->addWidget(mMessagePane
);
654 // add the preview window, if there is one
656 mSplitter2
->addWidget(mMsgView
);
659 } else { // short folder list
660 if (mReaderWindowBelow
) {
661 mSplitter1
->setOrientation(Qt::Vertical
);
662 mSplitter2
->setOrientation(Qt::Horizontal
);
663 } else { // at side or none
664 mSplitter1
->setOrientation(Qt::Horizontal
);
665 mSplitter2
->setOrientation(Qt::Vertical
);
668 mSplitter1
->addWidget(mSplitter2
);
671 mSplitter2
->addWidget(folderTreeWidget
);
672 // add message list to splitter 2
673 mSplitter2
->addWidget(mMessagePane
);
675 // add the preview window, if there is one
677 mSplitter1
->addWidget(mMsgView
);
682 // Set splitter properties
684 mSplitter1
->setObjectName(QStringLiteral("splitter1"));
685 //mSplitter1->setChildrenCollapsible( false );
686 mSplitter2
->setObjectName(QStringLiteral("splitter2"));
687 //mSplitter2->setChildrenCollapsible( false );
690 // Set the stretch factors
692 mSplitter1
->setStretchFactor(0, 0);
693 mSplitter2
->setStretchFactor(0, 0);
694 mSplitter1
->setStretchFactor(1, 1);
695 mSplitter2
->setStretchFactor(1, 1);
697 if (mFavoriteCollectionsView
) {
698 mFolderViewSplitter
->setStretchFactor(0, 0);
699 mFolderViewSplitter
->setStretchFactor(1, 1);
702 // Because the reader windows's width increases a tiny bit after each
703 // restart in short folder list mode with message window at side, disable
704 // the stretching as a workaround here
705 if (readerWindowAtSide
&& !mLongFolderList
) {
706 mSplitter1
->setStretchFactor(0, 1);
707 mSplitter1
->setStretchFactor(1, 0);
711 // Set the sizes of the splitters to the values stored in the config
713 QList
<int> splitter1Sizes
;
714 QList
<int> splitter2Sizes
;
716 const int folderViewWidth
= KMailSettings::self()->folderViewWidth();
717 int ftHeight
= KMailSettings::self()->folderTreeHeight();
718 int headerHeight
= KMailSettings::self()->searchAndHeaderHeight();
719 const int messageViewerWidth
= KMailSettings::self()->readerWindowWidth();
720 int headerWidth
= KMailSettings::self()->searchAndHeaderWidth();
721 int messageViewerHeight
= KMailSettings::self()->readerWindowHeight();
723 int ffvHeight
= mFolderViewSplitter
? MailCommon::MailCommonSettings::self()->favoriteCollectionViewHeight() : 0;
725 // If the message viewer was hidden before, make sure it is not zero height
726 if (messageViewerHeight
< 10 && readerWindowBelow
) {
728 messageViewerHeight
= headerHeight
;
731 if (mLongFolderList
) {
732 if (!readerWindowAtSide
) {
733 splitter1Sizes
<< folderViewWidth
<< headerWidth
;
734 splitter2Sizes
<< headerHeight
<< messageViewerHeight
;
736 splitter1Sizes
<< folderViewWidth
<< (headerWidth
+ messageViewerWidth
);
737 splitter2Sizes
<< headerWidth
<< messageViewerWidth
;
740 if (!readerWindowAtSide
) {
741 splitter1Sizes
<< headerHeight
<< messageViewerHeight
;
742 splitter2Sizes
<< folderViewWidth
<< headerWidth
;
744 splitter1Sizes
<< headerWidth
<< messageViewerWidth
;
745 splitter2Sizes
<< ftHeight
+ ffvHeight
<< messageViewerHeight
;
749 mSplitter1
->setSizes(splitter1Sizes
);
750 mSplitter2
->setSizes(splitter2Sizes
);
752 if (mFolderViewSplitter
) {
753 QList
<int> splitterSizes
;
754 splitterSizes
<< ffvHeight
<< ftHeight
;
755 mFolderViewSplitter
->setSizes(splitterSizes
);
759 // Now add the splitters to the main layout
761 mTopLayout
->addWidget(mSplitter1
);
763 // Make sure the focus is on the view, and not on the quick search line edit, because otherwise
764 // shortcuts like + or j go to the wrong place.
765 // This would normally be done in the message list itself, but apparently something resets the focus
766 // again, probably all the reparenting we do here.
767 mMessagePane
->focusView();
769 // By default hide th unread and size columns on first run.
770 if (kmkernel
->firstStart()) {
771 mFolderTreeWidget
->folderTreeView()->hideColumn(1);
772 mFolderTreeWidget
->folderTreeView()->hideColumn(3);
773 mFolderTreeWidget
->folderTreeView()->header()->resizeSection(0, folderViewWidth
* 0.8);
776 // Make the copy action work, see disconnect comment above
778 connect(mMsgView
->copyAction(), &QAction::triggered
,
779 mMsgView
, &KMReaderWin::slotCopySelectedText
);
782 //-----------------------------------------------------------------------------
783 void KMMainWidget::refreshFavoriteFoldersViewProperties()
785 if (mFavoriteCollectionsView
) {
786 if (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode
) {
787 mFavoriteCollectionsView
->changeViewMode(QListView::IconMode
);
788 } else if (MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode
) {
789 mFavoriteCollectionsView
->changeViewMode(QListView::ListMode
);
791 Q_ASSERT(false); // we should never get here in hidden mode
793 mFavoriteCollectionsView
->setDropActionMenuEnabled(kmkernel
->showPopupAfterDnD());
794 mFavoriteCollectionsView
->setWordWrap(true);
795 mFavoriteCollectionsView
->updateMode();
799 //-----------------------------------------------------------------------------
800 void KMMainWidget::readConfig()
802 const bool oldLongFolderList
= mLongFolderList
;
803 const bool oldReaderWindowActive
= mReaderWindowActive
;
804 const bool oldReaderWindowBelow
= mReaderWindowBelow
;
805 const bool oldFavoriteFolderView
= mEnableFavoriteFolderView
;
806 const bool oldFolderQuickSearch
= mEnableFolderQuickSearch
;
808 // on startup, the layout is always new and we need to relayout the widgets
809 bool layoutChanged
= !mStartupDone
;
814 layoutChanged
= (oldLongFolderList
!= mLongFolderList
) ||
815 (oldReaderWindowActive
!= mReaderWindowActive
) ||
816 (oldReaderWindowBelow
!= mReaderWindowBelow
) ||
817 (oldFavoriteFolderView
!= mEnableFavoriteFolderView
);
822 restoreCollectionFolderViewConfig();
823 Q_EMIT
recreateGui();
824 } else if (oldFolderQuickSearch
!= mEnableFolderQuickSearch
) {
825 if (mEnableFolderQuickSearch
) {
826 mFolderTreeWidget
->filterFolderLineEdit()->show();
828 mFolderTreeWidget
->filterFolderLineEdit()->hide();
834 // Read the config of the folder views and the header
836 mMsgView
->readConfig();
838 mMessagePane
->reloadGlobalConfiguration();
839 mFolderTreeWidget
->readConfig();
840 if (mFavoriteCollectionsView
) {
841 mFavoriteCollectionsView
->readConfig();
843 refreshFavoriteFoldersViewProperties();
847 // area for config group "General"
849 // check mail on startup
850 // do it after building the kmmainwin, so that the progressdialog is available
851 QTimer::singleShot(0, this, &KMMainWidget::slotCheckMailOnStartup
);
861 kmkernel
->toggleSystemTray();
862 mAccountActionMenu
->setAccountOrder(MailCommon::MailCommonSettings::self()->order());
864 connect(Akonadi::AgentManager::self(), &AgentManager::instanceAdded
,
865 this, &KMMainWidget::updateFileMenu
);
866 connect(Akonadi::AgentManager::self(), &AgentManager::instanceRemoved
,
867 this, &KMMainWidget::updateFileMenu
);
870 //-----------------------------------------------------------------------------
871 void KMMainWidget::writeConfig(bool force
)
873 // Don't save the sizes of all the widgets when we were never shown.
874 // This can happen in Kontact, where the KMail plugin is automatically
875 // loaded, but not necessarily shown.
876 // This prevents invalid sizes from being saved
878 // The height of the header widget can be 0, this happens when the user
879 // did not switch to the header widget onced and the "Welcome to KMail"
880 // HTML widget was shown the whole time
881 int headersHeight
= mMessagePane
->height();
882 if (headersHeight
== 0) {
883 headersHeight
= height() / 2;
886 KMailSettings::self()->setSearchAndHeaderHeight(headersHeight
);
887 KMailSettings::self()->setSearchAndHeaderWidth(mMessagePane
->width());
888 if (mFavoriteCollectionsView
) {
889 MailCommon::MailCommonSettings::self()->setFavoriteCollectionViewHeight(mFavoriteCollectionsView
->height());
890 KMailSettings::self()->setFolderTreeHeight(mFolderTreeWidget
->height());
891 if (!mLongFolderList
) {
892 KMailSettings::self()->setFolderViewHeight(mFolderViewSplitter
->height());
894 } else if (!mLongFolderList
&& mFolderTreeWidget
) {
895 KMailSettings::self()->setFolderTreeHeight(mFolderTreeWidget
->height());
897 if (mFolderTreeWidget
) {
898 KMailSettings::self()->setFolderViewWidth(mFolderTreeWidget
->width());
899 KSharedConfig::Ptr config
= KMKernel::self()->config();
900 KConfigGroup
group(config
, "CollectionFolderView");
902 ETMViewStateSaver saver
;
903 saver
.setView(mFolderTreeWidget
->folderTreeView());
904 saver
.saveState(group
);
906 group
.writeEntry("HeaderState", mFolderTreeWidget
->folderTreeView()->header()->saveState());
907 //Work around from startup folder
908 group
.deleteEntry("Selection");
910 if (!KMailSettings::self()->startSpecificFolderAtStartup()) {
911 group
.deleteEntry("Current");
918 if (!mReaderWindowBelow
) {
919 KMailSettings::self()->setReaderWindowWidth(mMsgView
->width());
921 mMsgView
->viewer()->writeConfig(force
);
922 KMailSettings::self()->setReaderWindowHeight(mMsgView
->height());
927 void KMMainWidget::writeReaderConfig()
931 mMsgView
->viewer()->writeConfig();
936 KMReaderWin
*KMMainWidget::messageView() const
941 CollectionPane
*KMMainWidget::messageListPane() const
946 //-----------------------------------------------------------------------------
947 void KMMainWidget::deleteWidgets()
949 // Simply delete the top splitter, which always is mSplitter1, regardless
950 // of the layout. This deletes all children.
951 // akonadi action manager is created in createWidgets(), parented to this
952 // so not autocleaned up.
953 delete mAkonadiStandardActionManager
;
954 mAkonadiStandardActionManager
= Q_NULLPTR
;
956 mMsgView
= Q_NULLPTR
;
957 mSearchAndTree
= Q_NULLPTR
;
958 mFolderViewSplitter
= Q_NULLPTR
;
959 mFavoriteCollectionsView
= Q_NULLPTR
;
960 mSplitter1
= Q_NULLPTR
;
961 mSplitter2
= Q_NULLPTR
;
962 mFavoritesModel
= Q_NULLPTR
;
965 //-----------------------------------------------------------------------------
966 void KMMainWidget::createWidgets()
968 // Note that all widgets we create in this function have the parent 'this'.
969 // They will be properly reparented in layoutSplitters()
972 // Create header view and search bar
974 FolderTreeWidget::TreeViewOptions opt
= FolderTreeWidget::ShowUnreadCount
;
975 opt
|= FolderTreeWidget::UseLineEditForFiltering
;
976 opt
|= FolderTreeWidget::ShowCollectionStatisticAnimation
;
977 opt
|= FolderTreeWidget::DontKeyFilter
;
978 mFolderTreeWidget
= new FolderTreeWidget(this, mGUIClient
, opt
);
980 connect(mFolderTreeWidget
->folderTreeView(), SIGNAL(currentChanged(Akonadi::Collection
)), this, SLOT(slotFolderChanged(Akonadi::Collection
)));
982 connect(mFolderTreeWidget
->folderTreeView()->selectionModel(), &QItemSelectionModel::selectionChanged
, this, &KMMainWidget::updateFolderMenu
);
984 connect(mFolderTreeWidget
->folderTreeView(), &FolderTreeView::prefereCreateNewTab
, this, &KMMainWidget::slotCreateNewTab
);
986 mFolderTreeWidget
->setSelectionMode(QAbstractItemView::ExtendedSelection
);
987 mMessagePane
= new CollectionPane(!KMailSettings::self()->startSpecificFolderAtStartup(), KMKernel::self()->entityTreeModel(),
988 mFolderTreeWidget
->folderTreeView()->selectionModel(),
990 connect(KMKernel::self()->entityTreeModel(), &Akonadi::EntityTreeModel::collectionFetched
, this, &KMMainWidget::slotCollectionFetched
);
992 mMessagePane
->setXmlGuiClient(mGUIClient
);
993 connect(mMessagePane
, &MessageList::Pane::messageSelected
,
994 this, &KMMainWidget::slotMessageSelected
);
995 connect(mMessagePane
, &MessageList::Pane::selectionChanged
,
996 this, &KMMainWidget::startUpdateMessageActionsTimer
);
997 connect(mMessagePane
, &CollectionPane::currentTabChanged
, this, &KMMainWidget::refreshMessageListSelection
);
998 connect(mMessagePane
, &MessageList::Pane::messageActivated
,
999 this, &KMMainWidget::slotMessageActivated
);
1000 connect(mMessagePane
, &MessageList::Pane::messageStatusChangeRequest
,
1001 this, &KMMainWidget::slotMessageStatusChangeRequest
);
1003 connect(mMessagePane
, &MessageList::Pane::statusMessage
,
1004 BroadcastStatus::instance(), &KPIM::BroadcastStatus::setStatusMsg
);
1007 // Create the reader window
1009 if (mReaderWindowActive
) {
1010 mMsgView
= new KMReaderWin(this, this, actionCollection(), Q_NULLPTR
);
1012 mMsgActions
->setMessageView(mMsgView
);
1014 connect(mMsgView
->viewer(), &MessageViewer::Viewer::replaceMsgByUnencryptedVersion
,
1015 this, &KMMainWidget::slotReplaceMsgByUnencryptedVersion
);
1016 connect(mMsgView
->viewer(), &MessageViewer::Viewer::popupMenu
,
1017 this, &KMMainWidget::slotMessagePopup
);
1018 connect(mMsgView
->viewer(), &MessageViewer::Viewer::moveMessageToTrash
,
1019 this, &KMMainWidget::slotMoveMessageToTrash
);
1020 if (mShowIntroductionAction
) {
1021 mShowIntroductionAction
->setEnabled(true);
1025 mMsgActions
->setMessageView(Q_NULLPTR
);
1027 if (mShowIntroductionAction
) {
1028 mShowIntroductionAction
->setEnabled(false);
1033 // Create the folder tree
1034 // the "folder tree" consists of a quicksearch input field and the tree itself
1037 mSearchAndTree
= new QWidget(this);
1038 QVBoxLayout
*vboxlayout
= new QVBoxLayout
;
1039 vboxlayout
->setMargin(0);
1040 mSearchAndTree
->setLayout(vboxlayout
);
1042 vboxlayout
->addWidget(mFolderTreeWidget
);
1044 if (!KMailSettings::self()->enableFolderQuickSearch()) {
1045 mFolderTreeWidget
->filterFolderLineEdit()->hide();
1048 // Create the favorite folder view
1050 mAkonadiStandardActionManager
= new Akonadi::StandardMailActionManager(mGUIClient
->actionCollection(), this);
1051 connect(mAkonadiStandardActionManager
, &Akonadi::StandardMailActionManager::actionStateUpdated
, this, &KMMainWidget::slotAkonadiStandardActionUpdated
);
1053 mAkonadiStandardActionManager
->setCollectionSelectionModel(mFolderTreeWidget
->folderTreeView()->selectionModel());
1054 mAkonadiStandardActionManager
->setItemSelectionModel(mMessagePane
->currentItemSelectionModel());
1056 if (mEnableFavoriteFolderView
) {
1058 mFavoriteCollectionsView
= new FavoriteCollectionWidget(mGUIClient
, this);
1059 refreshFavoriteFoldersViewProperties();
1060 connect(mFavoriteCollectionsView
, SIGNAL(currentChanged(Akonadi::Collection
)), this, SLOT(slotFolderChanged(Akonadi::Collection
)));
1062 mFavoritesModel
= new Akonadi::FavoriteCollectionsModel(
1063 mFolderTreeWidget
->folderTreeView()->model(),
1064 KMKernel::self()->config()->group("FavoriteCollections"), this);
1066 mFavoriteCollectionsView
->setModel(mFavoritesModel
);
1068 mAkonadiStandardActionManager
->setFavoriteCollectionsModel(mFavoritesModel
);
1069 mAkonadiStandardActionManager
->setFavoriteSelectionModel(mFavoriteCollectionsView
->selectionModel());
1072 //Don't use mMailActionManager->createAllActions() to save memory by not
1073 //creating actions that doesn't make sense.
1074 QList
<StandardActionManager::Type
> standardActions
;
1075 standardActions
<< StandardActionManager::CreateCollection
1076 << StandardActionManager::CopyCollections
1077 << StandardActionManager::DeleteCollections
1078 << StandardActionManager::SynchronizeCollections
1079 << StandardActionManager::CollectionProperties
1080 << StandardActionManager::CopyItems
1081 << StandardActionManager::Paste
1082 << StandardActionManager::DeleteItems
1083 << StandardActionManager::ManageLocalSubscriptions
1084 << StandardActionManager::CopyCollectionToMenu
1085 << StandardActionManager::CopyItemToMenu
1086 << StandardActionManager::MoveItemToMenu
1087 << StandardActionManager::MoveCollectionToMenu
1088 << StandardActionManager::CutItems
1089 << StandardActionManager::CutCollections
1090 << StandardActionManager::CreateResource
1091 << StandardActionManager::DeleteResources
1092 << StandardActionManager::ResourceProperties
1093 << StandardActionManager::SynchronizeResources
1094 << StandardActionManager::ToggleWorkOffline
1095 << StandardActionManager::SynchronizeCollectionsRecursive
;
1097 Q_FOREACH (StandardActionManager::Type standardAction
, standardActions
) {
1098 mAkonadiStandardActionManager
->createAction(standardAction
);
1101 if (mEnableFavoriteFolderView
) {
1102 QList
<StandardActionManager::Type
> favoriteActions
;
1103 favoriteActions
<< StandardActionManager::AddToFavoriteCollections
1104 << StandardActionManager::RemoveFromFavoriteCollections
1105 << StandardActionManager::RenameFavoriteCollection
1106 << StandardActionManager::SynchronizeFavoriteCollections
;
1107 Q_FOREACH (StandardActionManager::Type favoriteAction
, favoriteActions
) {
1108 mAkonadiStandardActionManager
->createAction(favoriteAction
);
1112 QList
<StandardMailActionManager::Type
> mailActions
;
1113 mailActions
<< StandardMailActionManager::MarkAllMailAsRead
1114 << StandardMailActionManager::MoveToTrash
1115 << StandardMailActionManager::MoveAllToTrash
1116 << StandardMailActionManager::RemoveDuplicates
1117 << StandardMailActionManager::EmptyAllTrash
1118 << StandardMailActionManager::MarkMailAsRead
1119 << StandardMailActionManager::MarkMailAsUnread
1120 << StandardMailActionManager::MarkMailAsImportant
1121 << StandardMailActionManager::MarkMailAsActionItem
;
1123 Q_FOREACH (StandardMailActionManager::Type mailAction
, mailActions
) {
1124 mAkonadiStandardActionManager
->createAction(mailAction
);
1127 mAkonadiStandardActionManager
->interceptAction(Akonadi::StandardActionManager::CollectionProperties
);
1128 connect(mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CollectionProperties
), &QAction::triggered
, mManageShowCollectionProperties
, &ManageShowCollectionProperties::slotCollectionProperties
);
1131 // Create all kinds of actions
1133 mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::RemoveDuplicates
)->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_Asterisk
));
1134 mAkonadiStandardActionManager
->interceptAction(Akonadi::StandardMailActionManager::RemoveDuplicates
);
1135 connect(mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::RemoveDuplicates
), &QAction::triggered
, this, &KMMainWidget::slotRemoveDuplicates
);
1138 mCollectionProperties
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CollectionProperties
);
1140 connect(kmkernel
->folderCollectionMonitor(), &Monitor::collectionRemoved
,
1141 this, &KMMainWidget::slotCollectionRemoved
);
1142 connect(kmkernel
->folderCollectionMonitor(), &Monitor::itemAdded
,
1143 this, &KMMainWidget::slotItemAdded
);
1144 connect(kmkernel
->folderCollectionMonitor(), &Monitor::itemRemoved
,
1145 this, &KMMainWidget::slotItemRemoved
);
1146 connect(kmkernel
->folderCollectionMonitor(), &Monitor::itemMoved
,
1147 this, &KMMainWidget::slotItemMoved
);
1148 connect(kmkernel
->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection
,QSet
<QByteArray
>)), SLOT(slotCollectionChanged(Akonadi::Collection
,QSet
<QByteArray
>)));
1150 connect(kmkernel
->folderCollectionMonitor(), &Monitor::collectionStatisticsChanged
, this, &KMMainWidget::slotCollectionStatisticsChanged
);
1154 void KMMainWidget::updateMoveAction(const Akonadi::CollectionStatistics
&statistic
)
1156 const bool hasUnreadMails
= (statistic
.unreadCount() > 0);
1157 const bool hasMails
= (statistic
.count() > 0);
1158 updateMoveAction(hasUnreadMails
, hasMails
);
1161 void KMMainWidget::updateMoveAction(bool hasUnreadMails
, bool hasMails
)
1163 const bool enable_goto_unread
= hasUnreadMails
1164 || (KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders
)
1165 || (KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders
);
1166 actionCollection()->action(QStringLiteral("go_next_message"))->setEnabled(hasMails
);
1167 actionCollection()->action(QStringLiteral("go_next_unread_message"))->setEnabled(enable_goto_unread
);
1168 actionCollection()->action(QStringLiteral("go_prev_message"))->setEnabled(hasMails
);
1169 actionCollection()->action(QStringLiteral("go_prev_unread_message"))->setEnabled(enable_goto_unread
);
1170 if (mAkonadiStandardActionManager
&& mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MarkAllMailAsRead
)) {
1171 mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MarkAllMailAsRead
)->setEnabled(hasUnreadMails
);
1175 void KMMainWidget::updateAllToTrashAction(int statistics
)
1177 bool multiFolder
= false;
1178 if (mFolderTreeWidget
) {
1179 multiFolder
= mFolderTreeWidget
->selectedCollections().count() > 1;
1181 if (mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MoveAllToTrash
)) {
1182 const bool folderWithContent
= mCurrentFolder
&& !mCurrentFolder
->isStructural();
1183 mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MoveAllToTrash
)->setEnabled(folderWithContent
1185 && mCurrentFolder
->canDeleteMessages()
1190 void KMMainWidget::slotCollectionStatisticsChanged(Akonadi::Collection::Id id
, const Akonadi::CollectionStatistics
&statistic
)
1192 if (id
== CommonKernel
->outboxCollectionFolder().id()) {
1193 const bool enableAction
= (statistic
.count() > 0);
1194 mSendQueued
->setEnabled(enableAction
);
1195 mSendActionMenu
->setEnabled(enableAction
);
1196 } else if (mCurrentFolder
&& (id
== mCurrentFolder
->collection().id())) {
1197 updateMoveAction(statistic
);
1198 updateAllToTrashAction(statistic
.count());
1199 mCurrentFolder
->setCollection(MailCommon::Util::updatedCollection(mCurrentFolder
->collection()));
1203 void KMMainWidget::slotCreateNewTab(bool preferNewTab
)
1205 mMessagePane
->setPreferEmptyTab(preferNewTab
);
1208 void KMMainWidget::slotCollectionChanged(const Akonadi::Collection
&collection
, const QSet
<QByteArray
> &set
)
1211 && (collection
== mCurrentFolder
->collection())
1212 && (set
.contains("MESSAGEFOLDER") || set
.contains("expirationcollectionattribute"))) {
1213 if (set
.contains("MESSAGEFOLDER")) {
1214 mMessagePane
->resetModelStorage();
1216 mCurrentFolder
->setCollection(collection
);
1218 } else if (set
.contains("ENTITYDISPLAY") || set
.contains("NAME")) {
1219 const QModelIndex idx
= Akonadi::EntityTreeModel::modelIndexForCollection(KMKernel::self()->collectionModel(), collection
);
1220 if (idx
.isValid()) {
1221 const QString text
= idx
.data().toString();
1222 const QIcon icon
= idx
.data(Qt::DecorationRole
).value
<QIcon
>();
1223 mMessagePane
->updateTabIconText(collection
, text
, icon
);
1228 void KMMainWidget::slotItemAdded(const Akonadi::Item
&msg
, const Akonadi::Collection
&col
)
1231 if (col
.isValid()) {
1232 if (col
== CommonKernel
->outboxCollectionFolder()) {
1233 startUpdateMessageActionsTimer();
1238 void KMMainWidget::slotItemRemoved(const Akonadi::Item
&item
)
1240 if (item
.isValid() && item
.parentCollection().isValid() && (item
.parentCollection() == CommonKernel
->outboxCollectionFolder())) {
1241 startUpdateMessageActionsTimer();
1245 void KMMainWidget::slotItemMoved(const Akonadi::Item
&item
, const Akonadi::Collection
&from
, const Akonadi::Collection
&to
)
1247 if (item
.isValid() && ((from
.id() == CommonKernel
->outboxCollectionFolder().id())
1248 || to
.id() == CommonKernel
->outboxCollectionFolder().id())) {
1249 startUpdateMessageActionsTimer();
1253 //-------------------------------------------------------------------------
1254 void KMMainWidget::slotFocusQuickSearch()
1256 const QString text
= mMsgView
? mMsgView
->copyText() : QString();
1257 mMessagePane
->focusQuickSearch(text
);
1260 //-------------------------------------------------------------------------
1261 bool KMMainWidget::slotSearch()
1264 mSearchWin
= new SearchWindow(this, mCurrentFolder
? mCurrentFolder
->collection() : Akonadi::Collection());
1265 mSearchWin
->setModal(false);
1266 mSearchWin
->setObjectName(QStringLiteral("Search"));
1268 mSearchWin
->activateFolder(mCurrentFolder
? mCurrentFolder
->collection() : Akonadi::Collection());
1272 KWindowSystem::activateWindow(mSearchWin
->winId());
1276 //-----------------------------------------------------------------------------
1277 void KMMainWidget::slotHelp()
1279 KHelpClient::invokeHelp();
1282 //-----------------------------------------------------------------------------
1283 void KMMainWidget::slotFilter()
1285 FilterIf
->openFilterDialog(true);
1288 void KMMainWidget::slotManageSieveScripts()
1290 if (!kmkernel
->askToGoOnline()) {
1293 if (mManageSieveDialog
) {
1297 mManageSieveDialog
= new KSieveUi::ManageSieveScriptsDialog
;
1298 connect(mManageSieveDialog
.data(), &KSieveUi::ManageSieveScriptsDialog::finished
, this, &KMMainWidget::slotCheckVacation
);
1299 mManageSieveDialog
->show();
1302 //-----------------------------------------------------------------------------
1303 void KMMainWidget::slotCheckMail()
1305 kmkernel
->checkMail();
1308 //-----------------------------------------------------------------------------
1309 void KMMainWidget::slotCheckMailOnStartup()
1311 kmkernel
->checkMailOnStartup();
1314 void KMMainWidget::slotCompose()
1316 KMail::Composer
*win
;
1317 KMime::Message::Ptr
msg(new KMime::Message());
1319 bool forceCursorPosition
= false;
1320 if (mCurrentFolder
) {
1321 MessageHelper::initHeader(msg
, KMKernel::self()->identityManager(), mCurrentFolder
->identity());
1322 //Laurent: bug 289905
1324 if ( mCurrentFolder->collection().isValid() && mCurrentFolder->putRepliesInSameFolder() ) {
1325 KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Fcc", msg.get(), QString::number( mCurrentFolder->collection().id() ), "utf-8" );
1326 msg->setHeader( header );
1329 TemplateParser::TemplateParser
parser(msg
, TemplateParser::TemplateParser::NewMessage
);
1330 parser
.setIdentityManager(KMKernel::self()->identityManager());
1331 parser
.process(msg
, mCurrentFolder
->collection());
1332 win
= KMail::makeComposer(msg
, false, false, KMail::Composer::New
, mCurrentFolder
->identity());
1333 win
->setCollectionForNewMessage(mCurrentFolder
->collection());
1334 forceCursorPosition
= parser
.cursorPositionWasSet();
1336 MessageHelper::initHeader(msg
, KMKernel::self()->identityManager());
1337 TemplateParser::TemplateParser
parser(msg
, TemplateParser::TemplateParser::NewMessage
);
1338 parser
.setIdentityManager(KMKernel::self()->identityManager());
1339 parser
.process(KMime::Message::Ptr(), Akonadi::Collection());
1340 win
= KMail::makeComposer(msg
, false, false, KMail::Composer::New
);
1341 forceCursorPosition
= parser
.cursorPositionWasSet();
1343 if (forceCursorPosition
) {
1344 win
->setFocusToEditor();
1350 //-----------------------------------------------------------------------------
1351 // TODO: do we want the list sorted alphabetically?
1352 void KMMainWidget::slotShowNewFromTemplate()
1354 if (mCurrentFolder
) {
1355 const KIdentityManagement::Identity
&ident
=
1356 kmkernel
->identityManager()->identityForUoidOrDefault(mCurrentFolder
->identity());
1357 mTemplateFolder
= CommonKernel
->collectionFromId(ident
.templates().toLongLong());
1360 if (!mTemplateFolder
.isValid()) {
1361 mTemplateFolder
= CommonKernel
->templatesCollectionFolder();
1363 if (!mTemplateFolder
.isValid()) {
1367 mTemplateMenu
->menu()->clear();
1369 Akonadi::ItemFetchJob
*job
= new Akonadi::ItemFetchJob(mTemplateFolder
);
1370 job
->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent
);
1371 job
->fetchScope().fetchFullPayload();
1372 connect(job
, &Akonadi::ItemFetchJob::result
, this, &KMMainWidget::slotDelayedShowNewFromTemplate
);
1375 void KMMainWidget::slotDelayedShowNewFromTemplate(KJob
*job
)
1377 Akonadi::ItemFetchJob
*fetchJob
= qobject_cast
<Akonadi::ItemFetchJob
*>(job
);
1379 const Akonadi::Item::List items
= fetchJob
->items();
1380 const int numberOfItems
= items
.count();
1381 for (int idx
= 0; idx
< numberOfItems
; ++idx
) {
1382 KMime::Message::Ptr msg
= MessageCore::Util::message(items
.at(idx
));
1384 QString subj
= msg
->subject()->asUnicodeString();
1385 if (subj
.isEmpty()) {
1386 subj
= i18n("No Subject");
1389 QAction
*templateAction
= mTemplateMenu
->menu()->addAction(KStringHandler::rsqueeze(subj
.replace(QLatin1Char('&'), QStringLiteral("&&"))));
1391 var
.setValue(items
.at(idx
));
1392 templateAction
->setData(var
);
1396 // If there are no templates available, add a menu entry which informs
1397 // the user about this.
1398 if (mTemplateMenu
->menu()->actions().isEmpty()) {
1399 QAction
*noAction
= mTemplateMenu
->menu()->addAction(
1400 i18n("(no templates)"));
1401 noAction
->setEnabled(false);
1405 //-----------------------------------------------------------------------------
1406 void KMMainWidget::slotNewFromTemplate(QAction
*action
)
1409 if (!mTemplateFolder
.isValid()) {
1412 const Akonadi::Item item
= action
->data().value
<Akonadi::Item
>();
1413 newFromTemplate(item
);
1416 //-----------------------------------------------------------------------------
1417 void KMMainWidget::newFromTemplate(const Akonadi::Item
&msg
)
1419 if (!msg
.isValid()) {
1422 KMCommand
*command
= new KMUseTemplateCommand(this, msg
);
1426 //-----------------------------------------------------------------------------
1427 void KMMainWidget::slotPostToML()
1429 if (mCurrentFolder
&& mCurrentFolder
->isMailingListEnabled()) {
1430 if (KMail::Util::mailingListPost(mCurrentFolder
)) {
1437 void KMMainWidget::slotExpireFolder()
1439 if (!mCurrentFolder
) {
1442 bool mustDeleteExpirationAttribute
= false;
1443 MailCommon::ExpireCollectionAttribute
*attr
= MailCommon::Util::expirationCollectionAttribute(mCurrentFolder
->collection(), mustDeleteExpirationAttribute
);
1444 bool canBeExpired
= true;
1445 if (!attr
->isAutoExpire()) {
1446 canBeExpired
= false;
1447 } else if (attr
->unreadExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever
&&
1448 attr
->readExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever
) {
1449 canBeExpired
= false;
1452 if (!canBeExpired
) {
1453 const QString message
= i18n("This folder does not have any expiry options set");
1454 KMessageBox::information(this, message
);
1455 if (mustDeleteExpirationAttribute
) {
1461 if (KMailSettings::self()->warnBeforeExpire()) {
1462 const QString message
= i18n("<qt>Are you sure you want to expire the folder <b>%1</b>?</qt>",
1463 mCurrentFolder
->name().toHtmlEscaped());
1464 if (KMessageBox::warningContinueCancel(this, message
, i18n("Expire Folder"),
1465 KGuiItem(i18n("&Expire")))
1466 != KMessageBox::Continue
) {
1467 if (mustDeleteExpirationAttribute
) {
1474 MailCommon::Util::expireOldMessages(mCurrentFolder
->collection(), true /*immediate*/);
1475 if (mustDeleteExpirationAttribute
) {
1480 //-----------------------------------------------------------------------------
1481 void KMMainWidget::slotEmptyFolder()
1483 if (!mCurrentFolder
) {
1486 const bool isTrash
= CommonKernel
->folderIsTrash(mCurrentFolder
->collection());
1487 if (KMailSettings::self()->confirmBeforeEmpty()) {
1488 const QString title
= (isTrash
) ? i18n("Empty Trash") : i18n("Move to Trash");
1489 const QString text
= (isTrash
) ?
1490 i18n("Are you sure you want to empty the trash folder?") :
1491 i18n("<qt>Are you sure you want to move all messages from "
1492 "folder <b>%1</b> to the trash?</qt>", mCurrentFolder
->name().toHtmlEscaped());
1494 if (KMessageBox::warningContinueCancel(this, text
, title
, KGuiItem(title
, QStringLiteral("user-trash")))
1495 != KMessageBox::Continue
) {
1499 #ifndef QT_NO_CURSOR
1500 KPIM::KCursorSaver
busy(KPIM::KBusyPtr::busy());
1502 slotSelectAllMessages();
1504 /* Don't ask for confirmation again when deleting, the user has already
1506 slotDeleteMsg(false);
1508 slotTrashSelectedMessages();
1512 mMsgView
->clearCache();
1516 BroadcastStatus::instance()->setStatusMsg(i18n("Moved all messages to the trash"));
1519 updateMessageActions();
1521 // Disable empty trash/move all to trash action - we've just deleted/moved
1522 // all folder contents.
1523 mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MoveAllToTrash
)->setEnabled(false);
1526 //-----------------------------------------------------------------------------
1527 void KMMainWidget::slotArchiveFolder()
1529 if (mCurrentFolder
&& mCurrentFolder
->collection().isValid()) {
1530 KMail::ArchiveFolderDialog archiveDialog
;
1531 archiveDialog
.setFolder(mCurrentFolder
->collection());
1532 archiveDialog
.exec();
1536 //-----------------------------------------------------------------------------
1537 void KMMainWidget::slotRemoveFolder()
1539 if (!mCurrentFolder
) {
1542 if (!mCurrentFolder
->collection().isValid()) {
1545 if (mCurrentFolder
->isSystemFolder()) {
1548 if (mCurrentFolder
->isReadOnly()) {
1552 RemoveCollectionJob
*job
= new RemoveCollectionJob(this);
1553 connect(job
, &RemoveCollectionJob::clearCurrentFolder
, this, &KMMainWidget::slotClearCurrentFolder
);
1554 job
->setMainWidget(this);
1555 job
->setCurrentFolder(mCurrentFolder
->collection());
1559 void KMMainWidget::slotClearCurrentFolder()
1561 mCurrentFolder
.clear();
1564 //-----------------------------------------------------------------------------
1565 void KMMainWidget::slotExpireAll()
1567 if (KMailSettings::self()->warnBeforeExpire()) {
1568 const int ret
= KMessageBox::warningContinueCancel(KMainWindow::memberList().first(),
1569 i18n("Are you sure you want to expire all old messages?"),
1570 i18n("Expire Old Messages?"), KGuiItem(i18n("Expire")));
1571 if (ret
!= KMessageBox::Continue
) {
1576 kmkernel
->expireAllFoldersNow();
1579 //-----------------------------------------------------------------------------
1580 void KMMainWidget::slotOverrideHtmlLoadExt()
1582 if (mHtmlLoadExtGlobalSetting
== mFolderHtmlLoadExtPreference
) {
1583 int result
= KMessageBox::warningContinueCancel(this,
1584 // the warning text is taken from configuredialog.cpp:
1585 i18n("Loading external references in html mail will make you more vulnerable to "
1586 "\"spam\" and may increase the likelihood that your system will be "
1587 "compromised by other present and anticipated security exploits."),
1588 i18n("Security Warning"),
1589 KGuiItem(i18n("Load External References")),
1590 KStandardGuiItem::cancel(),
1591 QStringLiteral("OverrideHtmlLoadExtWarning"), Q_NULLPTR
);
1592 if (result
== KMessageBox::Cancel
) {
1593 mPreferHtmlLoadExtAction
->setChecked(false);
1597 mFolderHtmlLoadExtPreference
= !mFolderHtmlLoadExtPreference
;
1600 mMsgView
->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference
);
1601 mMsgView
->update(true);
1605 //-----------------------------------------------------------------------------
1606 void KMMainWidget::slotMessageQueuedOrDrafted()
1608 if (!CommonKernel
->folderIsDraftOrOutbox(mCurrentFolder
->collection())) {
1612 mMsgView
->update(true);
1616 //-----------------------------------------------------------------------------
1617 void KMMainWidget::slotForwardInlineMsg()
1619 if (!mCurrentFolder
) {
1623 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
1624 if (selectedMessages
.isEmpty()) {
1627 KMForwardCommand
*command
= new KMForwardCommand(
1628 this, selectedMessages
, mCurrentFolder
->identity()
1634 //-----------------------------------------------------------------------------
1635 void KMMainWidget::slotForwardAttachedMsg()
1637 if (!mCurrentFolder
) {
1641 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
1642 if (selectedMessages
.isEmpty()) {
1645 KMForwardAttachedCommand
*command
= new KMForwardAttachedCommand(
1646 this, selectedMessages
, mCurrentFolder
->identity()
1652 //-----------------------------------------------------------------------------
1653 void KMMainWidget::slotUseTemplate()
1655 newFromTemplate(mMessagePane
->currentItem());
1658 //-----------------------------------------------------------------------------
1659 void KMMainWidget::slotResendMsg()
1661 const Akonadi::Item msg
= mMessagePane
->currentItem();
1662 if (!msg
.isValid()) {
1665 KMCommand
*command
= new KMResendMessageCommand(this, msg
);
1670 //-----------------------------------------------------------------------------
1671 // Message moving and permanent deletion
1674 void KMMainWidget::moveMessageSelected(MessageList::Core::MessageItemSetReference ref
, const Akonadi::Collection
&dest
, bool confirmOnDeletion
)
1676 Akonadi::Item::List selectMsg
= mMessagePane
->itemListFromPersistentSet(ref
);
1677 // If this is a deletion, ask for confirmation
1678 if (confirmOnDeletion
) {
1679 int ret
= KMessageBox::warningContinueCancel(
1682 "<qt>Do you really want to delete the selected message?<br />"
1683 "Once deleted, it cannot be restored.</qt>",
1684 "<qt>Do you really want to delete the %1 selected messages?<br />"
1685 "Once deleted, they cannot be restored.</qt>",
1688 selectMsg
.count() > 1 ? i18n("Delete Messages") : i18n("Delete Message"),
1689 KStandardGuiItem::del(),
1690 KStandardGuiItem::cancel(),
1691 QStringLiteral("NoConfirmDelete")
1693 if (ret
== KMessageBox::Cancel
) {
1694 mMessagePane
->deletePersistentSet(ref
);
1695 return; // user canceled the action
1698 mMessagePane
->markMessageItemsAsAboutToBeRemoved(ref
, true);
1699 // And stuff them into a KMMoveCommand :)
1700 KMMoveCommand
*command
= new KMMoveCommand(dest
, selectMsg
, ref
);
1702 command
, &KMMoveCommand::moveDone
,
1703 this, &KMMainWidget::slotMoveMessagesCompleted
1707 if (dest
.isValid()) {
1708 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages..."));
1710 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages..."));
1714 void KMMainWidget::slotMoveMessagesCompleted(KMMoveCommand
*command
)
1717 mMessagePane
->markMessageItemsAsAboutToBeRemoved(command
->refSet(), false);
1718 mMessagePane
->deletePersistentSet(command
->refSet());
1720 const bool moveWasReallyADelete
= !command
->destFolder().isValid();
1722 if (command
->result() == KMCommand::OK
) {
1723 if (moveWasReallyADelete
) {
1724 BroadcastStatus::instance()->setStatusMsg(i18n("Messages deleted successfully."));
1726 BroadcastStatus::instance()->setStatusMsg(i18n("Messages moved successfully."));
1729 if (moveWasReallyADelete
) {
1730 if (command
->result() == KMCommand::Failed
) {
1731 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages failed."));
1733 BroadcastStatus::instance()->setStatusMsg(i18n("Deleting messages canceled."));
1736 if (command
->result() == KMCommand::Failed
) {
1737 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages failed."));
1739 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages canceled."));
1743 // The command will autodelete itself and will also kill the set.
1746 void KMMainWidget::slotDeleteMessages()
1748 slotDeleteMsg(true);
1751 void KMMainWidget::slotDeleteMsg(bool confirmDelete
)
1753 // Create a persistent message set from the current selection
1754 MessageList::Core::MessageItemSetReference ref
= mMessagePane
->selectionAsPersistentSet();
1756 moveMessageSelected(ref
, Akonadi::Collection(), confirmDelete
);
1760 void KMMainWidget::slotDeleteThread(bool confirmDelete
)
1762 // Create a persistent set from the current thread.
1763 MessageList::Core::MessageItemSetReference ref
= mMessagePane
->currentThreadAsPersistentSet();
1765 moveMessageSelected(ref
, Akonadi::Collection(), confirmDelete
);
1769 FolderSelectionDialog
*KMMainWidget::moveOrCopyToDialog()
1771 if (!mMoveOrCopyToDialog
) {
1772 FolderSelectionDialog::SelectionFolderOption options
= FolderSelectionDialog::HideVirtualFolder
;
1773 mMoveOrCopyToDialog
= new FolderSelectionDialog(this, options
);
1774 mMoveOrCopyToDialog
->setModal(true);
1776 return mMoveOrCopyToDialog
;
1779 FolderSelectionDialog
*KMMainWidget::selectFromAllFoldersDialog()
1781 if (!mSelectFromAllFoldersDialog
) {
1782 FolderSelectionDialog::SelectionFolderOptions options
= FolderSelectionDialog::None
;
1783 options
|= FolderSelectionDialog::NotAllowToCreateNewFolder
;
1785 mSelectFromAllFoldersDialog
= new FolderSelectionDialog(this, options
);
1786 mSelectFromAllFoldersDialog
->setModal(true);
1788 return mSelectFromAllFoldersDialog
;
1791 void KMMainWidget::slotMoveSelectedMessageToFolder()
1793 QPointer
<MailCommon::FolderSelectionDialog
> dialog(moveOrCopyToDialog());
1794 dialog
->setWindowTitle(i18n("Move Messages to Folder"));
1795 if (dialog
->exec() && dialog
) {
1796 const Akonadi::Collection dest
= dialog
->selectedCollection();
1797 if (dest
.isValid()) {
1798 moveSelectedMessagesToFolder(dest
);
1803 void KMMainWidget::moveSelectedMessagesToFolder(const Akonadi::Collection
&dest
)
1805 MessageList::Core::MessageItemSetReference ref
= mMessagePane
->selectionAsPersistentSet();
1807 //Need to verify if dest == src ??? akonadi do it for us.
1808 moveMessageSelected(ref
, dest
, false);
1812 void KMMainWidget::copyMessageSelected(const Akonadi::Item::List
&selectMsg
, const Akonadi::Collection
&dest
)
1814 if (selectMsg
.isEmpty()) {
1817 // And stuff them into a KMCopyCommand :)
1818 KMCommand
*command
= new KMCopyCommand(dest
, selectMsg
);
1820 command
, &KMCommand::completed
,
1821 this, &KMMainWidget::slotCopyMessagesCompleted
1824 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages..."));
1827 void KMMainWidget::slotCopyMessagesCompleted(KMCommand
*command
)
1830 if (command
->result() == KMCommand::OK
) {
1831 BroadcastStatus::instance()->setStatusMsg(i18n("Messages copied successfully."));
1833 if (command
->result() == KMCommand::Failed
) {
1834 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages failed."));
1836 BroadcastStatus::instance()->setStatusMsg(i18n("Copying messages canceled."));
1839 // The command will autodelete itself and will also kill the set.
1842 void KMMainWidget::slotCopySelectedMessagesToFolder()
1844 QPointer
<MailCommon::FolderSelectionDialog
> dialog(moveOrCopyToDialog());
1845 dialog
->setWindowTitle(i18n("Copy Messages to Folder"));
1847 if (dialog
->exec() && dialog
) {
1848 const Akonadi::Collection dest
= dialog
->selectedCollection();
1849 if (dest
.isValid()) {
1850 copySelectedMessagesToFolder(dest
);
1855 void KMMainWidget::copySelectedMessagesToFolder(const Akonadi::Collection
&dest
)
1857 const Akonadi::Item::List lstMsg
= mMessagePane
->selectionAsMessageItemList();
1858 if (!lstMsg
.isEmpty()) {
1859 copyMessageSelected(lstMsg
, dest
);
1863 //-----------------------------------------------------------------------------
1866 void KMMainWidget::trashMessageSelected(MessageList::Core::MessageItemSetReference ref
)
1868 if (!mCurrentFolder
) {
1872 const Akonadi::Item::List select
= mMessagePane
->itemListFromPersistentSet(ref
);
1873 mMessagePane
->markMessageItemsAsAboutToBeRemoved(ref
, true);
1875 // FIXME: Why we don't use KMMoveCommand( trashFolder(), selectedMessages ); ?
1876 // And stuff them into a KMTrashMsgCommand :)
1877 KMCommand
*command
= new KMTrashMsgCommand(mCurrentFolder
->collection(), select
, ref
);
1880 command
, SIGNAL(moveDone(KMMoveCommand
*)),
1881 this, SLOT(slotTrashMessagesCompleted(KMMoveCommand
*))
1884 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash..."));
1887 void KMMainWidget::slotTrashMessagesCompleted(KMMoveCommand
*command
)
1890 mMessagePane
->markMessageItemsAsAboutToBeRemoved(command
->refSet(), false);
1891 mMessagePane
->deletePersistentSet(command
->refSet());
1892 if (command
->result() == KMCommand::OK
) {
1893 BroadcastStatus::instance()->setStatusMsg(i18n("Messages moved to trash successfully."));
1895 if (command
->result() == KMCommand::Failed
) {
1896 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash failed."));
1898 BroadcastStatus::instance()->setStatusMsg(i18n("Moving messages to trash canceled."));
1902 // The command will autodelete itself and will also kill the set.
1905 void KMMainWidget::slotTrashSelectedMessages()
1907 MessageList::Core::MessageItemSetReference ref
= mMessagePane
->selectionAsPersistentSet();
1909 trashMessageSelected(ref
);
1913 void KMMainWidget::slotTrashThread()
1915 MessageList::Core::MessageItemSetReference ref
= mMessagePane
->currentThreadAsPersistentSet();
1917 trashMessageSelected(ref
);
1921 //-----------------------------------------------------------------------------
1922 // Message tag setting for messages
1924 // FIXME: The "selection" version of these functions is in MessageActions.
1925 // We should probably move everything there....
1926 void KMMainWidget::toggleMessageSetTag(const Akonadi::Item::List
&select
, const Akonadi::Tag
&tag
)
1928 if (select
.isEmpty()) {
1931 KMCommand
*command
= new KMSetTagCommand(Akonadi::Tag::List() << tag
, select
, KMSetTagCommand::Toggle
);
1935 void KMMainWidget::slotSelectMoreMessageTagList()
1937 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
1938 if (selectedMessages
.isEmpty()) {
1942 TagSelectDialog
dlg(this, selectedMessages
.count(), selectedMessages
.first());
1943 dlg
.setActionCollection(QList
<KActionCollection
*>() << actionCollection());
1945 const Akonadi::Tag::List lst
= dlg
.selectedTag();
1946 KMCommand
*command
= new KMSetTagCommand(lst
, selectedMessages
, KMSetTagCommand::CleanExistingAndAddNew
);
1951 void KMMainWidget::slotUpdateMessageTagList(const Akonadi::Tag
&tag
)
1953 // Create a persistent set from the current thread.
1954 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
1955 if (selectedMessages
.isEmpty()) {
1958 toggleMessageSetTag(selectedMessages
, tag
);
1961 void KMMainWidget::refreshMessageListSelection()
1963 mAkonadiStandardActionManager
->setItemSelectionModel(mMessagePane
->currentItemSelectionModel());
1964 slotMessageSelected(mMessagePane
->currentItem());
1967 //-----------------------------------------------------------------------------
1968 // Status setting for threads
1970 // FIXME: The "selection" version of these functions is in MessageActions.
1971 // We should probably move everything there....
1972 void KMMainWidget::setMessageSetStatus(const Akonadi::Item::List
&select
,
1973 const Akonadi::MessageStatus
&status
,
1976 KMCommand
*command
= new KMSetStatusCommand(status
, select
, toggle
);
1980 void KMMainWidget::setCurrentThreadStatus(const Akonadi::MessageStatus
&status
, bool toggle
)
1982 const Akonadi::Item::List select
= mMessagePane
->currentThreadAsMessageList();
1983 if (select
.isEmpty()) {
1986 setMessageSetStatus(select
, status
, toggle
);
1989 void KMMainWidget::slotSetThreadStatusUnread()
1991 setCurrentThreadStatus(MessageStatus::statusRead(), true);
1994 void KMMainWidget::slotSetThreadStatusImportant()
1996 setCurrentThreadStatus(MessageStatus::statusImportant(), true);
1999 void KMMainWidget::slotSetThreadStatusRead()
2001 setCurrentThreadStatus(MessageStatus::statusRead(), false);
2004 void KMMainWidget::slotSetThreadStatusToAct()
2006 setCurrentThreadStatus(MessageStatus::statusToAct(), true);
2009 void KMMainWidget::slotSetThreadStatusWatched()
2011 setCurrentThreadStatus(MessageStatus::statusWatched(), true);
2012 if (mWatchThreadAction
->isChecked()) {
2013 mIgnoreThreadAction
->setChecked(false);
2017 void KMMainWidget::slotSetThreadStatusIgnored()
2019 setCurrentThreadStatus(MessageStatus::statusIgnored(), true);
2020 if (mIgnoreThreadAction
->isChecked()) {
2021 mWatchThreadAction
->setChecked(false);
2025 //-----------------------------------------------------------------------------
2026 void KMMainWidget::slotRedirectMsg()
2028 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
2029 if (selectedMessages
.isEmpty()) {
2033 KMCommand
*command
= new KMRedirectCommand(this, selectedMessages
);
2037 //-----------------------------------------------------------------------------
2038 void KMMainWidget::slotCustomReplyToMsg(const QString
&tmpl
)
2040 const Akonadi::Item msg
= mMessagePane
->currentItem();
2041 if (!msg
.isValid()) {
2045 const QString text
= mMsgView
? mMsgView
->copyText() : QString();
2047 qCDebug(KMAIL_LOG
) << "Reply with template:" << tmpl
;
2049 KMCommand
*command
= new KMReplyCommand(this,
2051 MessageComposer::ReplySmart
,
2057 //-----------------------------------------------------------------------------
2058 void KMMainWidget::slotCustomReplyAllToMsg(const QString
&tmpl
)
2060 const Akonadi::Item msg
= mMessagePane
->currentItem();
2061 if (!msg
.isValid()) {
2065 const QString text
= mMsgView
? mMsgView
->copyText() : QString();
2067 qCDebug(KMAIL_LOG
) << "Reply to All with template:" << tmpl
;
2069 KMCommand
*command
= new KMReplyCommand(this,
2071 MessageComposer::ReplyAll
,
2080 //-----------------------------------------------------------------------------
2081 void KMMainWidget::slotCustomForwardMsg(const QString
&tmpl
)
2083 if (!mCurrentFolder
) {
2087 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
2088 if (selectedMessages
.isEmpty()) {
2092 qCDebug(KMAIL_LOG
) << "Forward with template:" << tmpl
;
2093 KMForwardCommand
*command
= new KMForwardCommand(
2094 this, selectedMessages
, mCurrentFolder
->identity(), tmpl
2100 void KMMainWidget::openFilterDialog(const QByteArray
&field
, const QString
&value
)
2102 FilterIf
->openFilterDialog(false);
2103 FilterIf
->createFilter(field
, value
);
2106 //-----------------------------------------------------------------------------
2107 void KMMainWidget::slotSubjectFilter()
2109 const KMime::Message::Ptr msg
= mMessagePane
->currentMessage();
2114 openFilterDialog("Subject", msg
->subject()->asUnicodeString());
2117 //-----------------------------------------------------------------------------
2118 void KMMainWidget::slotFromFilter()
2120 KMime::Message::Ptr msg
= mMessagePane
->currentMessage();
2125 AddrSpecList al
= MessageHelper::extractAddrSpecs(msg
, "From");
2127 openFilterDialog("From", msg
->from()->asUnicodeString());
2129 openFilterDialog("From", al
.front().asString());
2133 //-----------------------------------------------------------------------------
2134 void KMMainWidget::slotToFilter()
2136 KMime::Message::Ptr msg
= mMessagePane
->currentMessage();
2140 openFilterDialog("To", msg
->to()->asUnicodeString());
2143 void KMMainWidget::slotCcFilter()
2145 KMime::Message::Ptr msg
= mMessagePane
->currentMessage();
2149 openFilterDialog("Cc", msg
->cc()->asUnicodeString());
2152 void KMMainWidget::slotBandwidth(bool b
)
2154 PimCommon::NetworkUtil::self()->setLowBandwidth(b
);
2157 //-----------------------------------------------------------------------------
2158 void KMMainWidget::slotUndo()
2160 kmkernel
->undoStack()->undo();
2161 updateMessageActions();
2165 //-----------------------------------------------------------------------------
2166 void KMMainWidget::slotJumpToFolder()
2168 QPointer
<MailCommon::FolderSelectionDialog
> dialog(selectFromAllFoldersDialog());
2169 dialog
->setWindowTitle(i18n("Jump to Folder"));
2170 if (dialog
->exec() && dialog
) {
2171 Akonadi::Collection collection
= dialog
->selectedCollection();
2172 if (collection
.isValid()) {
2173 slotSelectCollectionFolder(collection
);
2178 void KMMainWidget::slotSelectCollectionFolder(const Akonadi::Collection
&col
)
2180 if (mFolderTreeWidget
) {
2181 mFolderTreeWidget
->selectCollectionFolder(col
);
2182 slotFolderChanged(col
);
2186 void KMMainWidget::slotApplyFilters()
2188 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
2189 if (selectedMessages
.isEmpty()) {
2192 applyFilters(selectedMessages
);
2195 void KMMainWidget::slotApplyFiltersOnFolder()
2197 if (mCurrentFolder
&& mCurrentFolder
->collection().isValid()) {
2198 Akonadi::ItemFetchJob
*job
= new Akonadi::ItemFetchJob(mCurrentFolder
->collection(), this);
2199 connect(job
, &Akonadi::ItemFetchJob::result
, this, &KMMainWidget::slotFetchItemsForFolderDone
);
2203 void KMMainWidget::slotFetchItemsForFolderDone(KJob
*job
)
2205 Akonadi::ItemFetchJob
*fjob
= dynamic_cast<Akonadi::ItemFetchJob
*>(job
);
2207 Akonadi::Item::List items
= fjob
->items();
2208 applyFilters(items
);
2211 void KMMainWidget::applyFilters(const Akonadi::Item::List
&selectedMessages
)
2213 #ifndef QT_NO_CURSOR
2214 KPIM::KCursorSaver
busy(KPIM::KBusyPtr::busy());
2217 MailCommon::FilterManager::instance()->filter(selectedMessages
);
2220 //-----------------------------------------------------------------------------
2221 void KMMainWidget::slotCheckVacation()
2223 updateVacationScriptStatus(false);
2224 if (!kmkernel
->askToGoOnline()) {
2228 mVacationManager
->checkVacation();
2229 connect(mVacationManager
, SIGNAL(updateVacationScriptStatus(bool,QString
)), SLOT(updateVacationScriptStatus(bool,QString
)));
2230 connect(mVacationManager
, SIGNAL(editVacation()), SLOT(slotEditVacation()));
2233 void KMMainWidget::slotEditVacation(const QString
&serverName
)
2235 if (!kmkernel
->askToGoOnline()) {
2239 mVacationManager
->slotEditVacation(serverName
);
2242 //-----------------------------------------------------------------------------
2243 void KMMainWidget::slotDebugSieve()
2245 #if !defined(NDEBUG)
2246 if (mSieveDebugDialog
) {
2250 mSieveDebugDialog
= new KSieveUi::SieveDebugDialog(this);
2251 mSieveDebugDialog
->exec();
2252 delete mSieveDebugDialog
;
2256 void KMMainWidget::slotConfigChanged()
2259 mMsgActions
->setupForwardActions(actionCollection());
2260 mMsgActions
->setupForwardingActionsList(mGUIClient
);
2263 //-----------------------------------------------------------------------------
2264 void KMMainWidget::slotSaveMsg()
2266 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
2267 if (selectedMessages
.isEmpty()) {
2270 KMSaveMsgCommand
*saveCommand
= new KMSaveMsgCommand(this, selectedMessages
);
2271 saveCommand
->start();
2274 //-----------------------------------------------------------------------------
2275 void KMMainWidget::slotOpenMsg()
2277 KMOpenMsgCommand
*openCommand
= new KMOpenMsgCommand(this, QUrl(), overrideEncoding(), this);
2279 openCommand
->start();
2282 //-----------------------------------------------------------------------------
2283 void KMMainWidget::slotSaveAttachments()
2285 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
2286 if (selectedMessages
.isEmpty()) {
2289 // Avoid re-downloading in the common case that only one message is selected, and the message
2290 // is also displayed in the viewer. For this, create a dummy item without a parent collection / item id,
2291 // so that KMCommand doesn't download it.
2292 KMSaveAttachmentsCommand
*saveCommand
= Q_NULLPTR
;
2293 if (mMsgView
&& selectedMessages
.size() == 1 &&
2294 mMsgView
->message().hasPayload
<KMime::Message::Ptr
>() &&
2295 selectedMessages
.first().id() == mMsgView
->message().id()) {
2296 Akonadi::Item dummyItem
;
2297 dummyItem
.setPayload
<KMime::Message::Ptr
>(mMsgView
->message().payload
<KMime::Message::Ptr
>());
2298 saveCommand
= new KMSaveAttachmentsCommand(this, dummyItem
, mMsgView
->viewer());
2300 saveCommand
= new KMSaveAttachmentsCommand(this, selectedMessages
);
2303 saveCommand
->start();
2306 void KMMainWidget::slotOnlineStatus()
2308 // KMKernel will Q_EMIT a signal when we toggle the network state that is caught by
2309 // KMMainWidget::slotUpdateOnlineStatus to update our GUI
2310 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Online
) {
2311 // if online; then toggle and set it offline.
2312 kmkernel
->stopNetworkJobs();
2314 kmkernel
->resumeNetworkJobs();
2315 slotCheckVacation();
2319 void KMMainWidget::slotUpdateOnlineStatus(KMailSettings::EnumNetworkState::type
)
2321 if (!mAkonadiStandardActionManager
) {
2324 QAction
*action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::ToggleWorkOffline
);
2325 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Online
) {
2326 action
->setText(i18n("Work Offline"));
2327 action
->setIcon(QIcon::fromTheme(QStringLiteral("user-offline")));
2329 action
->setText(i18n("Work Online"));
2330 action
->setIcon(QIcon::fromTheme(QStringLiteral("user-online")));
2334 //-----------------------------------------------------------------------------
2335 void KMMainWidget::slotSendQueued()
2337 if (kmkernel
->msgSender()) {
2338 kmkernel
->msgSender()->sendQueued();
2342 //-----------------------------------------------------------------------------
2343 void KMMainWidget::slotSendQueuedVia(MailTransport::Transport
*transport
)
2346 if (kmkernel
->msgSender()) {
2347 kmkernel
->msgSender()->sendQueued(transport
->id());
2352 //-----------------------------------------------------------------------------
2353 void KMMainWidget::slotShowBusySplash()
2355 if (mReaderWindowActive
) {
2356 mMsgView
->displayBusyPage();
2360 void KMMainWidget::showOfflinePage()
2362 if (!mReaderWindowActive
) {
2366 mMsgView
->displayOfflinePage();
2369 void KMMainWidget::showResourceOfflinePage()
2371 if (!mReaderWindowActive
) {
2375 mMsgView
->displayResourceOfflinePage();
2378 //-----------------------------------------------------------------------------
2379 void KMMainWidget::slotReplaceMsgByUnencryptedVersion()
2382 Akonadi::Item oldMsg
= mMessagePane
->currentItem();
2383 if (oldMsg
.isValid()) {
2385 qCDebug(KMAIL_LOG
) << "Old message found";
2386 if (oldMsg
->hasUnencryptedMsg()) {
2387 qCDebug(KMAIL_LOG
) << "Extra unencrypted message found";
2388 KMime::Message
*newMsg
= oldMsg
->unencryptedMsg();
2389 // adjust the message id
2391 QString
msgId(oldMsg
->msgId());
2392 QString
prefix("DecryptedMsg.");
2393 int oldIdx
= msgId
.indexOf(prefix
, 0, Qt::CaseInsensitive
);
2395 int leftAngle
= msgId
.lastIndexOf('<');
2396 msgId
= msgId
.insert((-1 == leftAngle
) ? 0 : ++leftAngle
, prefix
);
2398 // toggle between "DecryptedMsg." and "DeCryptedMsg."
2399 // to avoid same message id
2400 QCharRef c
= msgId
[ oldIdx
+ 2 ];
2407 newMsg
->setMsgId(msgId
);
2408 mMsgView
->setIdOfLastViewedMessage(msgId
);
2410 // insert the unencrypted message
2411 qCDebug(KMAIL_LOG
) << "Adding unencrypted message to folder";
2412 mFolder
->addMsg(newMsg
);
2413 /* Figure out its index in the folder for selecting. This must be count()-1,
2414 * since we append. Be safe and do find, though, just in case. */
2415 int newMsgIdx
= mFolder
->find(newMsg
);
2416 Q_ASSERT(newMsgIdx
!= -1);
2417 /* we need this unget, to have the message displayed correctly initially */
2418 mFolder
->unGetMsg(newMsgIdx
);
2419 int idx
= mFolder
->find(oldMsg
);
2420 Q_ASSERT(idx
!= -1);
2421 /* only select here, so the old one is not un-Gotten before, which would
2422 * render the pointer we hold invalid so that find would fail */
2425 mHeaders
->setCurrentItemByIndex(newMsgIdx
);
2427 // remove the old one
2429 qCDebug(KMAIL_LOG
) << "Deleting encrypted message";
2433 qCDebug(KMAIL_LOG
) << "Updating message actions";
2434 updateMessageActions();
2436 qCDebug(KMAIL_LOG
) << "Done.";
2438 qCDebug(KMAIL_LOG
) << "NO EXTRA UNENCRYPTED MESSAGE FOUND";
2441 qCDebug(KMAIL_LOG
) << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO
;
2444 qCDebug(KMAIL_LOG
) << "PANIC: NO OLD MESSAGE FOUND";
2448 void KMMainWidget::slotFocusOnNextMessage()
2450 mMessagePane
->focusNextMessageItem(MessageList::Core::MessageTypeAny
, true, false);
2453 void KMMainWidget::slotFocusOnPrevMessage()
2455 mMessagePane
->focusPreviousMessageItem(MessageList::Core::MessageTypeAny
, true, false);
2458 void KMMainWidget::slotSelectFirstMessage()
2460 mMessagePane
->selectFirstMessageItem(MessageList::Core::MessageTypeAny
, true);
2463 void KMMainWidget::slotSelectLastMessage()
2465 mMessagePane
->selectLastMessageItem(MessageList::Core::MessageTypeAny
, true);
2468 void KMMainWidget::slotSelectFocusedMessage()
2470 mMessagePane
->selectFocusedMessageItem(true);
2473 void KMMainWidget::slotSelectNextMessage()
2475 mMessagePane
->selectNextMessageItem(MessageList::Core::MessageTypeAny
,
2476 MessageList::Core::ClearExistingSelection
,
2480 void KMMainWidget::slotExtendSelectionToNextMessage()
2482 mMessagePane
->selectNextMessageItem(
2483 MessageList::Core::MessageTypeAny
,
2484 MessageList::Core::GrowOrShrinkExistingSelection
,
2485 true, // center item
2486 false // don't loop in folder
2490 void KMMainWidget::slotSelectNextUnreadMessage()
2492 // The looping logic is: "Don't loop" just never loops, "Loop in current folder"
2493 // loops just in current folder, "Loop in all folders" loops in the current folder
2494 // first and then after confirmation jumps to the next folder.
2495 // A bad point here is that if you answer "No, and don't ask me again" to the confirmation
2496 // dialog then you have "Loop in current folder" and "Loop in all folders" that do
2497 // the same thing and no way to get the old behaviour. However, after a consultation on #kontact,
2498 // for bug-to-bug backward compatibility, the masters decided to keep it b0rken :D
2499 // If nobody complains, it stays like it is: if you complain enough maybe the masters will
2500 // decide to reconsider :)
2501 if (!mMessagePane
->selectNextMessageItem(
2502 MessageList::Core::MessageTypeUnreadOnly
,
2503 MessageList::Core::ClearExistingSelection
,
2504 true, // center item
2505 KMailSettings::self()->loopOnGotoUnread() != KMailSettings::EnumLoopOnGotoUnread::DontLoop
2507 // no next unread message was found in the current folder
2508 if ((KMailSettings::self()->loopOnGotoUnread() ==
2509 KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders
) ||
2510 (KMailSettings::self()->loopOnGotoUnread() ==
2511 KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders
)) {
2512 mGoToFirstUnreadMessageInSelectedFolder
= true;
2513 mFolderTreeWidget
->folderTreeView()->selectNextUnreadFolder(true);
2514 mGoToFirstUnreadMessageInSelectedFolder
= false;
2519 void KMMainWidget::slotSelectPreviousMessage()
2521 mMessagePane
->selectPreviousMessageItem(MessageList::Core::MessageTypeAny
,
2522 MessageList::Core::ClearExistingSelection
,
2526 void KMMainWidget::slotExtendSelectionToPreviousMessage()
2528 mMessagePane
->selectPreviousMessageItem(
2529 MessageList::Core::MessageTypeAny
,
2530 MessageList::Core::GrowOrShrinkExistingSelection
,
2531 true, // center item
2532 false // don't loop in folder
2536 void KMMainWidget::slotSelectPreviousUnreadMessage()
2538 if (!mMessagePane
->selectPreviousMessageItem(
2539 MessageList::Core::MessageTypeUnreadOnly
,
2540 MessageList::Core::ClearExistingSelection
,
2541 true, // center item
2542 KMailSettings::self()->loopOnGotoUnread() == KMailSettings::EnumLoopOnGotoUnread::LoopInCurrentFolder
2544 // no next unread message was found in the current folder
2545 if ((KMailSettings::self()->loopOnGotoUnread() ==
2546 KMailSettings::EnumLoopOnGotoUnread::LoopInAllFolders
) ||
2547 (KMailSettings::self()->loopOnGotoUnread() ==
2548 KMailSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders
)) {
2549 mGoToFirstUnreadMessageInSelectedFolder
= true;
2550 mFolderTreeWidget
->folderTreeView()->selectPrevUnreadFolder();
2551 mGoToFirstUnreadMessageInSelectedFolder
= false;
2556 void KMMainWidget::slotDisplayCurrentMessage()
2558 if (mMessagePane
->currentItem().isValid() && !mMessagePane
->searchEditHasFocus()) {
2559 slotMessageActivated(mMessagePane
->currentItem());
2563 // Called by double-clicked or 'Enter' in the messagelist -> pop up reader window
2564 void KMMainWidget::slotMessageActivated(const Akonadi::Item
&msg
)
2566 if (!mCurrentFolder
|| !msg
.isValid()) {
2570 if (CommonKernel
->folderIsDraftOrOutbox(mCurrentFolder
->collection())) {
2571 mMsgActions
->setCurrentMessage(msg
);
2572 mMsgActions
->editCurrentMessage();
2576 if (CommonKernel
->folderIsTemplates(mCurrentFolder
->collection())) {
2581 // Try to fetch the mail, even in offline mode, it might be cached
2582 KMFetchMessageCommand
*cmd
= new KMFetchMessageCommand(this, msg
);
2583 connect(cmd
, &KMCommand::completed
,
2584 this, &KMMainWidget::slotItemsFetchedForActivation
);
2588 void KMMainWidget::slotItemsFetchedForActivation(KMCommand
*command
)
2590 KMCommand::Result result
= command
->result();
2591 if (result
!= KMCommand::OK
) {
2592 qCDebug(KMAIL_LOG
) << "Result:" << result
;
2596 KMFetchMessageCommand
*fetchCmd
= qobject_cast
<KMFetchMessageCommand
*>(command
);
2597 const Item msg
= fetchCmd
->item();
2599 KMReaderMainWin
*win
= new KMReaderMainWin(mFolderDisplayFormatPreference
, mFolderHtmlLoadExtPreference
);
2600 const bool useFixedFont
= mMsgView
? mMsgView
->isFixedFont() :
2601 MessageViewer::MessageViewerSettings::self()->useFixedFont();
2602 win
->setUseFixedFont(useFixedFont
);
2604 const Akonadi::Collection parentCollection
= MailCommon::Util::parentCollectionFromItem(msg
);
2605 win
->showMessage(overrideEncoding(), msg
, parentCollection
);
2609 void KMMainWidget::slotMessageStatusChangeRequest(const Akonadi::Item
&item
, const Akonadi::MessageStatus
&set
, const Akonadi::MessageStatus
&clear
)
2611 if (!item
.isValid()) {
2615 if (clear
.toQInt32() != Akonadi::MessageStatus().toQInt32()) {
2616 KMCommand
*command
= new KMSetStatusCommand(clear
, Akonadi::Item::List() << item
, true);
2620 if (set
.toQInt32() != Akonadi::MessageStatus().toQInt32()) {
2621 KMCommand
*command
= new KMSetStatusCommand(set
, Akonadi::Item::List() << item
, false);
2626 //-----------------------------------------------------------------------------
2627 void KMMainWidget::slotSelectAllMessages()
2629 mMessagePane
->selectAll();
2630 updateMessageActions();
2633 void KMMainWidget::slotMessagePopup(const Akonadi::Item
&msg
, const QUrl
&aUrl
, const QUrl
&imageUrl
, const QPoint
&aPoint
)
2635 updateMessageMenu();
2637 const QString email
= KEmailAddress::firstEmailAddress(aUrl
.path()).toLower();
2638 if (aUrl
.scheme() == QLatin1String("mailto") && !email
.isEmpty()) {
2639 Akonadi::ContactSearchJob
*job
= new Akonadi::ContactSearchJob(this);
2641 job
->setQuery(Akonadi::ContactSearchJob::Email
, email
, Akonadi::ContactSearchJob::ExactMatch
);
2642 job
->setProperty("msg", QVariant::fromValue(msg
));
2643 job
->setProperty("point", aPoint
);
2644 job
->setProperty("imageUrl", imageUrl
);
2645 job
->setProperty("url", aUrl
);
2646 connect(job
, &Akonadi::ContactSearchJob::result
, this, &KMMainWidget::slotContactSearchJobForMessagePopupDone
);
2648 showMessagePopup(msg
, aUrl
, imageUrl
, aPoint
, false, false);
2652 void KMMainWidget::slotContactSearchJobForMessagePopupDone(KJob
*job
)
2654 const Akonadi::ContactSearchJob
*searchJob
= qobject_cast
<Akonadi::ContactSearchJob
*>(job
);
2655 const bool contactAlreadyExists
= !searchJob
->contacts().isEmpty();
2657 const Akonadi::Item::List listContact
= searchJob
->items();
2658 const bool uniqueContactFound
= (listContact
.count() == 1);
2659 if (uniqueContactFound
) {
2660 mMsgView
->setContactItem(listContact
.first(), searchJob
->contacts().at(0));
2662 mMsgView
->clearContactItem();
2664 const Akonadi::Item msg
= job
->property("msg").value
<Akonadi::Item
>();
2665 const QPoint aPoint
= job
->property("point").toPoint();
2666 const QUrl imageUrl
= job
->property("imageUrl").toUrl();
2667 const QUrl url
= job
->property("url").toUrl();
2669 showMessagePopup(msg
, url
, imageUrl
, aPoint
, contactAlreadyExists
, uniqueContactFound
);
2672 void KMMainWidget::showMessagePopup(const Akonadi::Item
&msg
, const QUrl
&url
, const QUrl
&imageUrl
, const QPoint
&aPoint
, bool contactAlreadyExists
, bool uniqueContactFound
)
2674 QMenu
*menu
= new QMenu
;
2676 bool urlMenuAdded
= false;
2678 if (!url
.isEmpty()) {
2679 if (url
.scheme() == QLatin1String("mailto")) {
2680 // popup on a mailto URL
2681 menu
->addAction(mMsgView
->mailToComposeAction());
2682 menu
->addAction(mMsgView
->mailToReplyAction());
2683 menu
->addAction(mMsgView
->mailToForwardAction());
2685 menu
->addSeparator();
2687 if (contactAlreadyExists
) {
2688 if (uniqueContactFound
) {
2689 menu
->addAction(mMsgView
->editContactAction());
2691 menu
->addAction(mMsgView
->openAddrBookAction());
2694 menu
->addAction(mMsgView
->addAddrBookAction());
2695 menu
->addAction(mMsgView
->addToExistingContactAction());
2697 menu
->addSeparator();
2698 menu
->addMenu(mMsgView
->viewHtmlOption());
2699 menu
->addSeparator();
2700 menu
->addAction(mMsgView
->copyURLAction());
2701 urlMenuAdded
= true;
2702 } else if (url
.scheme() != QLatin1String("attachment")) {
2703 // popup on a not-mailto URL
2704 menu
->addAction(mMsgView
->urlOpenAction());
2705 menu
->addAction(mMsgView
->addBookmarksAction());
2706 menu
->addAction(mMsgView
->urlSaveAsAction());
2707 menu
->addAction(mMsgView
->copyURLAction());
2708 menu
->addSeparator();
2709 menu
->addAction(mMsgView
->shareServiceUrlMenu());
2710 if (mMsgView
->isAShortUrl(url
)) {
2711 menu
->addSeparator();
2712 menu
->addAction(mMsgView
->expandShortUrlAction());
2714 if (!imageUrl
.isEmpty()) {
2715 menu
->addSeparator();
2716 menu
->addAction(mMsgView
->copyImageLocation());
2717 menu
->addAction(mMsgView
->downloadImageToDiskAction());
2718 menu
->addAction(mMsgView
->shareImage());
2719 if (mMsgView
->adblockEnabled()) {
2720 menu
->addSeparator();
2721 menu
->addAction(mMsgView
->blockImage());
2724 urlMenuAdded
= true;
2726 qCDebug(KMAIL_LOG
) << "URL is:" << url
;
2728 const QString selectedText
= mMsgView
? mMsgView
->copyText() : QString();
2729 if (mMsgView
&& !selectedText
.isEmpty()) {
2731 menu
->addSeparator();
2733 menu
->addAction(mMsgActions
->replyMenu());
2734 menu
->addSeparator();
2736 menu
->addAction(mMsgView
->copyAction());
2737 menu
->addAction(mMsgView
->selectAllAction());
2738 menu
->addSeparator();
2739 mMsgActions
->addWebShortcutsMenu(menu
, selectedText
);
2740 menu
->addSeparator();
2741 menu
->addActions(mMsgView
->viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedSelection
));
2742 if (KPIMTextEdit::TextToSpeech::self()->isReady()) {
2743 menu
->addSeparator();
2744 menu
->addAction(mMsgView
->speakTextAction());
2746 } else if (!urlMenuAdded
) {
2747 // popup somewhere else (i.e., not a URL) on the message
2748 if (!mMessagePane
->currentMessage()) {
2753 Akonadi::Collection parentCol
= msg
.parentCollection();
2754 if (parentCol
.isValid() && CommonKernel
->folderIsTemplates(parentCol
)) {
2755 menu
->addAction(mUseAction
);
2757 menu
->addAction(mMsgActions
->replyMenu());
2758 menu
->addAction(mMsgActions
->forwardMenu());
2760 if (parentCol
.isValid() && CommonKernel
->folderIsSentMailFolder(parentCol
)) {
2761 menu
->addAction(sendAgainAction());
2763 menu
->addAction(editAction());
2765 menu
->addAction(mailingListActionMenu());
2766 menu
->addSeparator();
2768 menu
->addAction(mCopyActionMenu
);
2769 menu
->addAction(mMoveActionMenu
);
2771 menu
->addSeparator();
2773 menu
->addAction(mMsgActions
->messageStatusMenu());
2774 menu
->addSeparator();
2776 if (!imageUrl
.isEmpty()) {
2777 menu
->addSeparator();
2778 menu
->addAction(mMsgView
->copyImageLocation());
2779 menu
->addAction(mMsgView
->downloadImageToDiskAction());
2780 menu
->addAction(mMsgView
->shareImage());
2781 menu
->addSeparator();
2782 if (mMsgView
->adblockEnabled()) {
2783 menu
->addAction(mMsgView
->blockImage());
2784 menu
->addSeparator();
2787 menu
->addAction(mMsgView
->viewSourceAction());
2788 menu
->addAction(mMsgView
->toggleFixFontAction());
2789 menu
->addAction(mMsgView
->toggleMimePartTreeAction());
2791 menu
->addSeparator();
2792 if (mMsgActions
->printPreviewAction()) {
2793 menu
->addAction(mMsgActions
->printPreviewAction());
2795 menu
->addAction(mMsgActions
->printAction());
2796 menu
->addAction(mSaveAsAction
);
2797 menu
->addAction(mSaveAttachmentsAction
);
2798 menu
->addSeparator();
2799 if (parentCol
.isValid() && CommonKernel
->folderIsTrash(parentCol
)) {
2800 menu
->addAction(mDeleteAction
);
2802 menu
->addAction(akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash
));
2804 menu
->addSeparator();
2807 menu
->addActions(mMsgView
->viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedMessage
));
2808 menu
->addSeparator();
2809 menu
->addAction(mMsgView
->saveMessageDisplayFormatAction());
2810 menu
->addAction(mMsgView
->resetMessageDisplayFormatAction());
2811 menu
->addSeparator();
2813 menu
->addAction(mMsgActions
->annotateAction());
2815 if (mMsgView
&& mMsgView
->adblockEnabled()) {
2816 menu
->addSeparator();
2817 menu
->addAction(mMsgView
->openBlockableItems());
2819 menu
->addSeparator();
2820 menu
->addAction(mMsgActions
->addFollowupReminderAction());
2821 if (kmkernel
->allowToDebugBalooSupport()) {
2822 menu
->addSeparator();
2823 menu
->addAction(mMsgActions
->debugBalooAction());
2826 KAcceleratorManager::manage(menu
);
2827 menu
->exec(aPoint
, Q_NULLPTR
);
2831 void KMMainWidget::setupActions()
2833 mMsgActions
= new KMail::MessageActions(actionCollection(), this);
2834 mMsgActions
->setMessageView(mMsgView
);
2837 mSaveAsAction
= new QAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save &As..."), this);
2838 actionCollection()->addAction(QStringLiteral("file_save_as"), mSaveAsAction
);
2839 connect(mSaveAsAction
, &QAction::triggered
, this, &KMMainWidget::slotSaveMsg
);
2840 actionCollection()->setDefaultShortcut(mSaveAsAction
, KStandardShortcut::save().first());
2842 mOpenAction
= KStandardAction::open(this, SLOT(slotOpenMsg()),
2843 actionCollection());
2845 mOpenRecentAction
= KStandardAction::openRecent(this, SLOT(slotOpenRecentMsg(QUrl
)),
2846 actionCollection());
2847 KConfigGroup grp
= mConfig
->group(QStringLiteral("Recent Files"));
2848 mOpenRecentAction
->loadEntries(grp
);
2851 QAction
*action
= new QAction(i18n("&Expire All Folders"), this);
2852 actionCollection()->addAction(QStringLiteral("expire_all_folders"), action
);
2853 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotExpireAll
);
2856 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("mail-receive")), i18n("Check &Mail"), this);
2857 actionCollection()->addAction(QStringLiteral("check_mail"), action
);
2858 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotCheckMail
);
2859 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_L
));
2862 mAccountActionMenu
= new KActionMenuAccount(this);
2863 mAccountActionMenu
->setIcon(QIcon::fromTheme(QStringLiteral("mail-receive")));
2864 mAccountActionMenu
->setText(i18n("Check Mail In"));
2866 mAccountActionMenu
->setIconText(i18n("Check Mail"));
2867 mAccountActionMenu
->setToolTip(i18n("Check Mail"));
2868 actionCollection()->addAction(QStringLiteral("check_mail_in"), mAccountActionMenu
);
2869 connect(mAccountActionMenu
, &KActionMenu::triggered
, this, &KMMainWidget::slotCheckMail
);
2871 mSendQueued
= new QAction(QIcon::fromTheme(QStringLiteral("mail-send")), i18n("&Send Queued Messages"), this);
2872 actionCollection()->addAction(QStringLiteral("send_queued"), mSendQueued
);
2873 connect(mSendQueued
, &QAction::triggered
, this, &KMMainWidget::slotSendQueued
);
2876 QAction
*action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::ToggleWorkOffline
);
2877 mAkonadiStandardActionManager
->interceptAction(Akonadi::StandardActionManager::ToggleWorkOffline
);
2878 action
->setCheckable(false);
2879 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotOnlineStatus
);
2880 action
->setText(i18n("Online status (unknown)"));
2883 mSendActionMenu
= new KActionMenuTransport(this);
2884 mSendActionMenu
->setIcon(QIcon::fromTheme(QStringLiteral("mail-send-via")));
2885 mSendActionMenu
->setText(i18n("Send Queued Messages Via"));
2886 actionCollection()->addAction(QStringLiteral("send_queued_via"), mSendActionMenu
);
2888 connect(mSendActionMenu
, &KActionMenuTransport::transportSelected
, this, &KMMainWidget::slotSendQueuedVia
);
2891 if (parent()->inherits("KMMainWin")) {
2892 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("x-office-address-book")), i18n("&Address Book"), this);
2893 actionCollection()->addAction(QStringLiteral("addressbook"), action
);
2894 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotAddrBook
);
2895 if (QStandardPaths::findExecutable(QStringLiteral("kaddressbook")).isEmpty()) {
2896 action
->setEnabled(false);
2901 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("pgp-keys")), i18n("Certificate Manager"), this);
2902 actionCollection()->addAction(QStringLiteral("tools_start_certman"), action
);
2903 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotStartCertManager
);
2904 // disable action if no certman binary is around
2905 if (QStandardPaths::findExecutable(QStringLiteral("kleopatra")).isEmpty()) {
2906 action
->setEnabled(false);
2910 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("pgp-keys")), i18n("GnuPG Log Viewer"), this);
2911 actionCollection()->addAction(QStringLiteral("tools_start_kwatchgnupg"), action
);
2912 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotStartWatchGnuPG
);
2914 // not ported yet, underlying infrastructure missing on Windows
2915 const bool usableKWatchGnupg
= false;
2917 // disable action if no kwatchgnupg binary is around
2918 bool usableKWatchGnupg
= !QStandardPaths::findExecutable(QStringLiteral("kwatchgnupg")).isEmpty();
2920 action
->setEnabled(usableKWatchGnupg
);
2923 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("document-import")), i18n("&Import Messages..."), this);
2924 actionCollection()->addAction(QStringLiteral("import"), action
);
2925 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotImport
);
2926 if (QStandardPaths::findExecutable(QStringLiteral("importwizard")).isEmpty()) {
2927 action
->setEnabled(false);
2931 #if !defined(NDEBUG)
2933 QAction
*action
= new QAction(i18n("&Debug Sieve..."), this);
2934 actionCollection()->addAction(QStringLiteral("tools_debug_sieve"), action
);
2935 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotDebugSieve
);
2940 QAction
*action
= new QAction(i18n("Filter &Log Viewer..."), this);
2941 actionCollection()->addAction(QStringLiteral("filter_log_viewer"), action
);
2942 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotFilterLogViewer
);
2945 QAction
*action
= new QAction(i18n("&Anti-Spam Wizard..."), this);
2946 actionCollection()->addAction(QStringLiteral("antiSpamWizard"), action
);
2947 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotAntiSpamWizard
);
2950 QAction
*action
= new QAction(i18n("&Anti-Virus Wizard..."), this);
2951 actionCollection()->addAction(QStringLiteral("antiVirusWizard"), action
);
2952 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotAntiVirusWizard
);
2955 QAction
*action
= new QAction(i18n("&Account Wizard..."), this);
2956 actionCollection()->addAction(QStringLiteral("accountWizard"), action
);
2957 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotAccountWizard
);
2960 QAction
*action
= new QAction(i18n("&Import Wizard..."), this);
2961 actionCollection()->addAction(QStringLiteral("importWizard"), action
);
2962 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotImportWizard
);
2964 if (KSieveUi::Util::allowOutOfOfficeSettings()) {
2965 QAction
*action
= new QAction(i18n("Edit \"Out of Office\" Replies..."), this);
2966 actionCollection()->addAction(QStringLiteral("tools_edit_vacation"), action
);
2967 connect(action
, SIGNAL(triggered(bool)), SLOT(slotEditVacation()));
2971 QAction
*action
= new QAction(i18n("&Configure Automatic Archiving..."), this);
2972 actionCollection()->addAction(QStringLiteral("tools_automatic_archiving"), action
);
2973 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotConfigureAutomaticArchiving
);
2977 QAction
*action
= new QAction(i18n("Delayed Messages..."), this);
2978 actionCollection()->addAction(QStringLiteral("message_delayed"), action
);
2979 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotConfigureSendLater
);
2983 QAction
*action
= new QAction(i18n("Followup Reminder Messages..."), this);
2984 actionCollection()->addAction(QStringLiteral("followup_reminder_messages"), action
);
2985 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotConfigureFollowupReminder
);
2988 // Disable the standard action delete key sortcut.
2989 QAction
*const standardDelAction
= akonadiStandardAction(Akonadi::StandardActionManager::DeleteItems
);
2990 standardDelAction
->setShortcut(QKeySequence());
2994 /* The delete action is nowhere in the gui, by default, so we need to make
2995 * sure it is plugged into the KAccel now, since that won't happen on
2996 * XMLGui construction or manual ->plug(). This is only a problem when run
2997 * as a part, though. */
2998 mDeleteAction
= new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@action Hard delete, bypassing trash", "&Delete"), this);
2999 actionCollection()->addAction(QStringLiteral("delete"), mDeleteAction
);
3000 connect(mDeleteAction
, &QAction::triggered
, this, &KMMainWidget::slotDeleteMessages
);
3001 actionCollection()->setDefaultShortcut(mDeleteAction
, QKeySequence(Qt::SHIFT
+ Qt::Key_Delete
));
3003 mTrashThreadAction
= new QAction(i18n("M&ove Thread to Trash"), this);
3004 actionCollection()->addAction(QStringLiteral("move_thread_to_trash"), mTrashThreadAction
);
3005 actionCollection()->setDefaultShortcut(mTrashThreadAction
, QKeySequence(Qt::CTRL
+ Qt::Key_Delete
));
3006 mTrashThreadAction
->setIcon(QIcon::fromTheme(QStringLiteral("user-trash")));
3007 KMail::Util::addQActionHelpText(mTrashThreadAction
, i18n("Move thread to trashcan"));
3008 connect(mTrashThreadAction
, &QAction::triggered
, this, &KMMainWidget::slotTrashThread
);
3010 mDeleteThreadAction
= new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete T&hread"), this);
3011 actionCollection()->addAction(QStringLiteral("delete_thread"), mDeleteThreadAction
);
3012 //Don't use new connect api.
3013 connect(mDeleteThreadAction
, SIGNAL(triggered(bool)), this, SLOT(slotDeleteThread()));
3014 actionCollection()->setDefaultShortcut(mDeleteThreadAction
, QKeySequence(Qt::CTRL
+ Qt::SHIFT
+ Qt::Key_Delete
));
3016 mSearchMessages
= new QAction(QIcon::fromTheme(QStringLiteral("edit-find-mail")), i18n("&Find Messages..."), this);
3017 actionCollection()->addAction(QStringLiteral("search_messages"), mSearchMessages
);
3018 connect(mSearchMessages
, &QAction::triggered
, this, &KMMainWidget::slotRequestFullSearchFromQuickSearch
);
3019 actionCollection()->setDefaultShortcut(mSearchMessages
, QKeySequence(Qt::Key_S
));
3022 QAction
*action
= new QAction(i18n("Select &All Messages"), this);
3023 actionCollection()->addAction(QStringLiteral("mark_all_messages"), action
);
3024 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotSelectAllMessages
);
3025 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_A
));
3030 mFolderMailingListPropertiesAction
= new QAction(i18n("&Mailing List Management..."), this);
3031 actionCollection()->addAction(QStringLiteral("folder_mailinglist_properties"), mFolderMailingListPropertiesAction
);
3032 connect(mFolderMailingListPropertiesAction
, &QAction::triggered
, mManageShowCollectionProperties
, &ManageShowCollectionProperties::slotFolderMailingListProperties
);
3033 // mFolderMailingListPropertiesAction->setIcon(QIcon::fromTheme("document-properties-mailing-list"));
3035 mShowFolderShortcutDialogAction
= new QAction(QIcon::fromTheme(QStringLiteral("configure-shortcuts")), i18n("&Assign Shortcut..."), this);
3036 actionCollection()->addAction(QStringLiteral("folder_shortcut_command"), mShowFolderShortcutDialogAction
);
3037 connect(mShowFolderShortcutDialogAction
, &QAction::triggered
, mManageShowCollectionProperties
,
3038 &ManageShowCollectionProperties::slotShowFolderShortcutDialog
);
3039 // FIXME: this action is not currently enabled in the rc file, but even if
3040 // it were there is inconsistency between the action name and action.
3041 // "Expiration Settings" implies that this will lead to a settings dialogue
3042 // and it should be followed by a "...", but slotExpireFolder() performs
3043 // an immediate expiry.
3045 // TODO: expire action should be disabled if there is no content or if
3046 // the folder can't delete messages.
3048 // Leaving the action here for the moment, it and the "Expire" option in the
3049 // folder popup menu should be combined or at least made consistent. Same for
3050 // slotExpireFolder() and FolderViewItem::slotShowExpiryProperties().
3051 mExpireFolderAction
= new QAction(i18n("&Expiration Settings"), this);
3052 actionCollection()->addAction(QStringLiteral("expire"), mExpireFolderAction
);
3053 connect(mExpireFolderAction
, &QAction::triggered
, this, &KMMainWidget::slotExpireFolder
);
3055 mAkonadiStandardActionManager
->interceptAction(Akonadi::StandardMailActionManager::MoveToTrash
);
3056 connect(mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MoveToTrash
), &QAction::triggered
, this, &KMMainWidget::slotTrashSelectedMessages
);
3058 mAkonadiStandardActionManager
->interceptAction(Akonadi::StandardMailActionManager::MoveAllToTrash
);
3059 connect(mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MoveAllToTrash
), &QAction::triggered
, this, &KMMainWidget::slotEmptyFolder
);
3061 mAkonadiStandardActionManager
->interceptAction(Akonadi::StandardActionManager::DeleteCollections
);
3062 connect(mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::DeleteCollections
), &QAction::triggered
, this, &KMMainWidget::slotRemoveFolder
);
3064 // ### PORT ME: Add this to the context menu. Not possible right now because
3065 // the context menu uses XMLGUI, and that would add the entry to
3066 // all collection context menus
3067 mArchiveFolderAction
= new QAction(i18n("&Archive Folder..."), this);
3068 actionCollection()->addAction(QStringLiteral("archive_folder"), mArchiveFolderAction
);
3069 connect(mArchiveFolderAction
, &QAction::triggered
, this, &KMMainWidget::slotArchiveFolder
);
3071 mDisplayMessageFormatMenu
= new DisplayMessageFormatActionMenu(this);
3072 connect(mDisplayMessageFormatMenu
, &DisplayMessageFormatActionMenu::changeDisplayMessageFormat
, this, &KMMainWidget::slotChangeDisplayMessageFormat
);
3073 actionCollection()->addAction(QStringLiteral("display_format_message"), mDisplayMessageFormatMenu
);
3075 mPreferHtmlLoadExtAction
= new KToggleAction(i18n("Load E&xternal References"), this);
3076 actionCollection()->addAction(QStringLiteral("prefer_html_external_refs"), mPreferHtmlLoadExtAction
);
3077 connect(mPreferHtmlLoadExtAction
, &KToggleAction::triggered
, this, &KMMainWidget::slotOverrideHtmlLoadExt
);
3080 QAction
*action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CopyCollections
);
3081 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::SHIFT
+ Qt::CTRL
+ Qt::Key_C
));
3084 QAction
*action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::Paste
);
3085 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::SHIFT
+ Qt::CTRL
+ Qt::Key_V
));
3088 QAction
*action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CopyItems
);
3089 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::ALT
+ Qt::CTRL
+ Qt::Key_C
));
3092 QAction
*action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CutItems
);
3093 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::ALT
+ Qt::CTRL
+ Qt::Key_X
));
3097 QAction
*action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CopyItemToMenu
);
3098 action
->setText(i18n("Copy Message To..."));
3099 action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::MoveItemToMenu
);
3100 action
->setText(i18n("Move Message To..."));
3103 //----- Message Menu
3105 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("mail-message-new")), i18n("&New Message..."), this);
3106 actionCollection()->addAction(QStringLiteral("new_message"), action
);
3107 action
->setIconText(i18nc("@action:intoolbar New Empty Message", "New"));
3108 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotCompose
);
3109 // do not set a New shortcut if kmail is a component
3110 if (!kmkernel
->xmlGuiInstanceName().isEmpty()) {
3111 actionCollection()->setDefaultShortcut(action
, KStandardShortcut::openNew().first());
3115 mTemplateMenu
= new KActionMenu(QIcon::fromTheme(QStringLiteral("document-new")), i18n("Message From &Template"),
3116 actionCollection());
3117 mTemplateMenu
->setDelayed(true);
3118 actionCollection()->addAction(QStringLiteral("new_from_template"), mTemplateMenu
);
3119 connect(mTemplateMenu
->menu(), &QMenu::aboutToShow
, this,
3120 &KMMainWidget::slotShowNewFromTemplate
);
3121 connect(mTemplateMenu
->menu(), &QMenu::triggered
, this,
3122 &KMMainWidget::slotNewFromTemplate
);
3124 mMessageNewList
= new QAction(QIcon::fromTheme(QStringLiteral("mail-message-new-list")),
3125 i18n("New Message t&o Mailing-List..."),
3127 actionCollection()->addAction(QStringLiteral("post_message"), mMessageNewList
);
3128 connect(mMessageNewList
, &QAction::triggered
,
3129 this, &KMMainWidget::slotPostToML
);
3130 actionCollection()->setDefaultShortcut(mMessageNewList
, QKeySequence(Qt::CTRL
+ Qt::SHIFT
+ Qt::Key_N
));
3132 mSendAgainAction
= new QAction(i18n("Send A&gain..."), this);
3133 actionCollection()->addAction(QStringLiteral("send_again"), mSendAgainAction
);
3134 connect(mSendAgainAction
, &QAction::triggered
, this, &KMMainWidget::slotResendMsg
);
3136 //----- Create filter actions
3137 mFilterMenu
= new KActionMenu(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("&Create Filter"), this);
3138 actionCollection()->addAction(QStringLiteral("create_filter"), mFilterMenu
);
3139 connect(mFilterMenu
, &QAction::triggered
, this,
3140 &KMMainWidget::slotFilter
);
3142 QAction
*action
= new QAction(i18n("Filter on &Subject..."), this);
3143 actionCollection()->addAction(QStringLiteral("subject_filter"), action
);
3144 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotSubjectFilter
);
3145 mFilterMenu
->addAction(action
);
3149 QAction
*action
= new QAction(i18n("Filter on &From..."), this);
3150 actionCollection()->addAction(QStringLiteral("from_filter"), action
);
3151 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotFromFilter
);
3152 mFilterMenu
->addAction(action
);
3155 QAction
*action
= new QAction(i18n("Filter on &To..."), this);
3156 actionCollection()->addAction(QStringLiteral("to_filter"), action
);
3157 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotToFilter
);
3158 mFilterMenu
->addAction(action
);
3161 QAction
*action
= new QAction(i18n("Filter on &Cc..."), this);
3162 actionCollection()->addAction(QStringLiteral("cc_filter"), action
);
3163 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotCcFilter
);
3164 mFilterMenu
->addAction(action
);
3166 mFilterMenu
->addAction(mMsgActions
->listFilterAction());
3168 mUseAction
= new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("New Message From &Template"), this);
3169 actionCollection()->addAction(QStringLiteral("use_template"), mUseAction
);
3170 connect(mUseAction
, &QAction::triggered
, this, &KMMainWidget::slotUseTemplate
);
3171 actionCollection()->setDefaultShortcut(mUseAction
, QKeySequence(Qt::SHIFT
+ Qt::Key_N
));
3173 //----- "Mark Thread" submenu
3174 mThreadStatusMenu
= new KActionMenu(i18n("Mark &Thread"), this);
3175 actionCollection()->addAction(QStringLiteral("thread_status"), mThreadStatusMenu
);
3177 mMarkThreadAsReadAction
= new QAction(QIcon::fromTheme(QStringLiteral("mail-mark-read")), i18n("Mark Thread as &Read"), this);
3178 actionCollection()->addAction(QStringLiteral("thread_read"), mMarkThreadAsReadAction
);
3179 connect(mMarkThreadAsReadAction
, &QAction::triggered
, this, &KMMainWidget::slotSetThreadStatusRead
);
3180 KMail::Util::addQActionHelpText(mMarkThreadAsReadAction
, i18n("Mark all messages in the selected thread as read"));
3181 mThreadStatusMenu
->addAction(mMarkThreadAsReadAction
);
3183 mMarkThreadAsUnreadAction
= new QAction(QIcon::fromTheme(QStringLiteral("mail-mark-unread")), i18n("Mark Thread as &Unread"), this);
3184 actionCollection()->addAction(QStringLiteral("thread_unread"), mMarkThreadAsUnreadAction
);
3185 connect(mMarkThreadAsUnreadAction
, &QAction::triggered
, this, &KMMainWidget::slotSetThreadStatusUnread
);
3186 KMail::Util::addQActionHelpText(mMarkThreadAsUnreadAction
, i18n("Mark all messages in the selected thread as unread"));
3187 mThreadStatusMenu
->addAction(mMarkThreadAsUnreadAction
);
3189 mThreadStatusMenu
->addSeparator();
3191 //----- "Mark Thread" toggle actions
3192 mToggleThreadImportantAction
= new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-mark-important")), i18n("Mark Thread as &Important"), this);
3193 actionCollection()->addAction(QStringLiteral("thread_flag"), mToggleThreadImportantAction
);
3194 connect(mToggleThreadImportantAction
, &KToggleAction::triggered
, this, &KMMainWidget::slotSetThreadStatusImportant
);
3195 mToggleThreadImportantAction
->setCheckedState(KGuiItem(i18n("Remove &Important Thread Mark")));
3196 mThreadStatusMenu
->addAction(mToggleThreadImportantAction
);
3198 mToggleThreadToActAction
= new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-mark-task")), i18n("Mark Thread as &Action Item"), this);
3199 actionCollection()->addAction(QStringLiteral("thread_toact"), mToggleThreadToActAction
);
3200 connect(mToggleThreadToActAction
, &KToggleAction::triggered
, this, &KMMainWidget::slotSetThreadStatusToAct
);
3201 mToggleThreadToActAction
->setCheckedState(KGuiItem(i18n("Remove &Action Item Thread Mark")));
3202 mThreadStatusMenu
->addAction(mToggleThreadToActAction
);
3204 //------- "Watch and ignore thread" actions
3205 mWatchThreadAction
= new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-thread-watch")), i18n("&Watch Thread"), this);
3206 actionCollection()->addAction(QStringLiteral("thread_watched"), mWatchThreadAction
);
3207 connect(mWatchThreadAction
, &KToggleAction::triggered
, this, &KMMainWidget::slotSetThreadStatusWatched
);
3209 mIgnoreThreadAction
= new KToggleAction(QIcon::fromTheme(QStringLiteral("mail-thread-ignored")), i18n("&Ignore Thread"), this);
3210 actionCollection()->addAction(QStringLiteral("thread_ignored"), mIgnoreThreadAction
);
3211 connect(mIgnoreThreadAction
, &KToggleAction::triggered
, this, &KMMainWidget::slotSetThreadStatusIgnored
);
3213 mThreadStatusMenu
->addSeparator();
3214 mThreadStatusMenu
->addAction(mWatchThreadAction
);
3215 mThreadStatusMenu
->addAction(mIgnoreThreadAction
);
3217 mSaveAttachmentsAction
= new QAction(QIcon::fromTheme(QStringLiteral("mail-attachment")), i18n("Save A&ttachments..."), this);
3218 actionCollection()->addAction(QStringLiteral("file_save_attachments"), mSaveAttachmentsAction
);
3219 connect(mSaveAttachmentsAction
, &QAction::triggered
, this, &KMMainWidget::slotSaveAttachments
);
3221 mMoveActionMenu
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::MoveItemToMenu
);
3223 mCopyActionMenu
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CopyItemToMenu
);
3225 mApplyAllFiltersAction
=
3226 new QAction(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("Appl&y All Filters"), this);
3227 actionCollection()->addAction(QStringLiteral("apply_filters"), mApplyAllFiltersAction
);
3228 connect(mApplyAllFiltersAction
, &QAction::triggered
,
3229 this, &KMMainWidget::slotApplyFilters
);
3230 actionCollection()->setDefaultShortcut(mApplyAllFiltersAction
, QKeySequence(Qt::CTRL
+ Qt::Key_J
));
3232 mApplyFilterActionsMenu
= new KActionMenu(i18n("A&pply Filter"), this);
3233 actionCollection()->addAction(QStringLiteral("apply_filter_actions"), mApplyFilterActionsMenu
);
3236 QAction
*action
= new QAction(i18nc("View->", "&Expand Thread / Group"), this);
3237 actionCollection()->addAction(QStringLiteral("expand_thread"), action
);
3238 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::Key_Period
));
3239 KMail::Util::addQActionHelpText(action
, i18n("Expand the current thread or group"));
3240 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotExpandThread
);
3243 QAction
*action
= new QAction(i18nc("View->", "&Collapse Thread / Group"), this);
3244 actionCollection()->addAction(QStringLiteral("collapse_thread"), action
);
3245 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::Key_Comma
));
3246 KMail::Util::addQActionHelpText(action
, i18n("Collapse the current thread or group"));
3247 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotCollapseThread
);
3250 QAction
*action
= new QAction(i18nc("View->", "Ex&pand All Threads"), this);
3251 actionCollection()->addAction(QStringLiteral("expand_all_threads"), action
);
3252 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_Period
));
3253 KMail::Util::addQActionHelpText(action
, i18n("Expand all threads in the current folder"));
3254 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotExpandAllThreads
);
3257 QAction
*action
= new QAction(i18nc("View->", "C&ollapse All Threads"), this);
3258 actionCollection()->addAction(QStringLiteral("collapse_all_threads"), action
);
3259 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_Comma
));
3260 KMail::Util::addQActionHelpText(action
, i18n("Collapse all threads in the current folder"));
3261 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotCollapseAllThreads
);
3264 QAction
*dukeOfMonmoth
= new QAction(i18n("&Display Message"), this);
3265 actionCollection()->addAction(QStringLiteral("display_message"), dukeOfMonmoth
);
3266 connect(dukeOfMonmoth
, &QAction::triggered
, this, &KMMainWidget::slotDisplayCurrentMessage
);
3267 QList
<QKeySequence
> shortcuts
;
3268 shortcuts
<< QKeySequence(Qt::Key_Enter
) << QKeySequence(Qt::Key_Return
);
3269 actionCollection()->setDefaultShortcuts(dukeOfMonmoth
, shortcuts
);
3273 QAction
*action
= new QAction(i18n("&Next Message"), this);
3274 actionCollection()->addAction(QStringLiteral("go_next_message"), action
);
3275 actionCollection()->setDefaultShortcut(action
, QKeySequence(QStringLiteral("N; Right")));
3276 KMail::Util::addQActionHelpText(action
, i18n("Go to the next message"));
3277 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotSelectNextMessage
);
3280 QAction
*action
= new QAction(i18n("Next &Unread Message"), this);
3281 actionCollection()->addAction(QStringLiteral("go_next_unread_message"), action
);
3282 actionCollection()->setDefaultShortcuts(action
, QList
<QKeySequence
>() << QKeySequence(Qt::Key_Plus
) << QKeySequence(Qt::Key_Plus
+ Qt::KeypadModifier
));
3283 if (QApplication::isRightToLeft()) {
3284 action
->setIcon(QIcon::fromTheme(QStringLiteral("go-previous")));
3286 action
->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
3288 action
->setIconText(i18nc("@action:inmenu Goto next unread message", "Next"));
3289 KMail::Util::addQActionHelpText(action
, i18n("Go to the next unread message"));
3290 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotSelectNextUnreadMessage
);
3293 QAction
*action
= new QAction(i18n("&Previous Message"), this);
3294 actionCollection()->addAction(QStringLiteral("go_prev_message"), action
);
3295 KMail::Util::addQActionHelpText(action
, i18n("Go to the previous message"));
3296 actionCollection()->setDefaultShortcut(action
, QKeySequence(QStringLiteral("P; Left")));
3297 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotSelectPreviousMessage
);
3300 QAction
*action
= new QAction(i18n("Previous Unread &Message"), this);
3301 actionCollection()->addAction(QStringLiteral("go_prev_unread_message"), action
);
3302 actionCollection()->setDefaultShortcuts(action
, QList
<QKeySequence
>() << QKeySequence(Qt::Key_Minus
) << QKeySequence(Qt::Key_Minus
+ Qt::KeypadModifier
));
3303 if (QApplication::isRightToLeft()) {
3304 action
->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
3306 action
->setIcon(QIcon::fromTheme(QStringLiteral("go-previous")));
3308 action
->setIconText(i18nc("@action:inmenu Goto previous unread message.", "Previous"));
3309 KMail::Util::addQActionHelpText(action
, i18n("Go to the previous unread message"));
3310 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotSelectPreviousUnreadMessage
);
3313 QAction
*action
= new QAction(i18n("Next Unread &Folder"), this);
3314 actionCollection()->addAction(QStringLiteral("go_next_unread_folder"), action
);
3315 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotNextUnreadFolder
);
3316 actionCollection()->setDefaultShortcuts(action
, QList
<QKeySequence
>() << QKeySequence(Qt::ALT
+ Qt::Key_Plus
) << QKeySequence(Qt::ALT
+ Qt::Key_Plus
+ Qt::KeypadModifier
));
3317 KMail::Util::addQActionHelpText(action
, i18n("Go to the next folder with unread messages"));
3320 QAction
*action
= new QAction(i18n("Previous Unread F&older"), this);
3321 actionCollection()->addAction(QStringLiteral("go_prev_unread_folder"), action
);
3322 actionCollection()->setDefaultShortcuts(action
, QList
<QKeySequence
>() << QKeySequence(Qt::ALT
+ Qt::Key_Minus
) << QKeySequence(Qt::ALT
+ Qt::Key_Minus
+ Qt::KeypadModifier
));
3323 KMail::Util::addQActionHelpText(action
, i18n("Go to the previous folder with unread messages"));
3324 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotPrevUnreadFolder
);
3327 QAction
*action
= new QAction(i18nc("Go->", "Next Unread &Text"), this);
3328 actionCollection()->addAction(QStringLiteral("go_next_unread_text"), action
);
3329 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::Key_Space
));
3330 KMail::Util::addQActionHelpText(action
, i18n("Go to the next unread text"));
3331 action
->setWhatsThis(i18n("Scroll down current message. "
3332 "If at end of current message, "
3333 "go to next unread message."));
3334 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotReadOn
);
3337 //----- Settings Menu
3339 QAction
*action
= new QAction(i18n("Configure &Filters..."), this);
3340 action
->setMenuRole(QAction::NoRole
); // do not move to application menu on OS X
3341 actionCollection()->addAction(QStringLiteral("filter"), action
);
3342 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotFilter
);
3345 QAction
*action
= new QAction(i18n("Manage &Sieve Scripts..."), this);
3346 actionCollection()->addAction(QStringLiteral("sieveFilters"), action
);
3347 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotManageSieveScripts
);
3350 mShowIntroductionAction
= new QAction(QIcon::fromTheme(QStringLiteral("kmail")), i18n("KMail &Introduction"), this);
3351 actionCollection()->addAction(QStringLiteral("help_kmail_welcomepage"), mShowIntroductionAction
);
3352 KMail::Util::addQActionHelpText(mShowIntroductionAction
, i18n("Display KMail's Welcome Page"));
3353 connect(mShowIntroductionAction
, &QAction::triggered
, this, &KMMainWidget::slotIntro
);
3354 mShowIntroductionAction
->setEnabled(mMsgView
!= Q_NULLPTR
);
3357 // ----- Standard Actions
3359 // KStandardAction::configureNotifications(this, SLOT(slotEditNotifications()), actionCollection());
3361 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("preferences-desktop-notification")),
3362 i18n("Configure &Notifications..."), this);
3363 action
->setMenuRole(QAction::NoRole
); // do not move to application menu on OS X
3364 actionCollection()->addAction(QStringLiteral("kmail_configure_notifications"), action
);
3365 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotEditNotifications
);
3369 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("&Configure KMail..."), this);
3370 action
->setMenuRole(QAction::PreferencesRole
); // this one should move to the application menu on OS X
3371 actionCollection()->addAction(QStringLiteral("kmail_configure_kmail"), action
);
3372 connect(action
, &QAction::triggered
, kmkernel
, &KMKernel::slotShowConfigurationDialog
);
3376 mExpireConfigAction
= new QAction(i18n("Expire..."), this);
3377 actionCollection()->addAction(QStringLiteral("expire_settings"), mExpireConfigAction
);
3378 connect(mExpireConfigAction
, &QAction::triggered
, mManageShowCollectionProperties
, &ManageShowCollectionProperties::slotShowExpiryProperties
);
3382 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("bookmark-new")), i18n("Add Favorite Folder..."), this);
3383 actionCollection()->addAction(QStringLiteral("add_favorite_folder"), action
);
3384 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotAddFavoriteFolder
);
3388 mServerSideSubscription
= new QAction(QIcon::fromTheme(QStringLiteral("folder-bookmarks")), i18n("Serverside Subscription..."), this);
3389 actionCollection()->addAction(QStringLiteral("serverside_subscription"), mServerSideSubscription
);
3390 connect(mServerSideSubscription
, &QAction::triggered
, this, &KMMainWidget::slotServerSideSubscription
);
3394 mApplyFiltersOnFolder
= new QAction(QIcon::fromTheme(QStringLiteral("view-filter")), i18n("Appl&y All Filters On Folder"), this);
3395 actionCollection()->addAction(QStringLiteral("apply_filters_on_folder"), mApplyFiltersOnFolder
);
3396 connect(mApplyFiltersOnFolder
, &QAction::triggered
,
3397 this, &KMMainWidget::slotApplyFiltersOnFolder
);
3402 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("kmail")), i18n("&Export KMail Data..."), this);
3403 actionCollection()->addAction(QStringLiteral("kmail_export_data"), action
);
3404 connect(action
, &QAction::triggered
, mLaunchExternalComponent
, &KMLaunchExternalComponent::slotExportData
);
3408 QAction
*action
= new QAction(QIcon::fromTheme(QStringLiteral("contact-new")), i18n("New AddressBook Contact..."), this);
3409 actionCollection()->addAction(QStringLiteral("kmail_new_addressbook_contact"), action
);
3410 connect(action
, &QAction::triggered
, this, &KMMainWidget::slotCreateAddressBookContact
);
3414 actionCollection()->addAction(KStandardAction::Undo
, QStringLiteral("kmail_undo"), this, SLOT(slotUndo()));
3416 menutimer
= new QTimer(this);
3417 menutimer
->setObjectName(QStringLiteral("menutimer"));
3418 menutimer
->setSingleShot(true);
3419 connect(menutimer
, &QTimer::timeout
, this, &KMMainWidget::updateMessageActionsDelayed
);
3420 connect(kmkernel
->undoStack(),
3421 &KMail::UndoStack::undoStackChanged
, this, &KMMainWidget::slotUpdateUndo
);
3423 updateMessageActions();
3425 mTagActionManager
= new KMail::TagActionManager(this, actionCollection(), mMsgActions
,
3427 mFolderShortcutActionManager
= new KMail::FolderShortcutActionManager(this, actionCollection());
3430 QAction
*action
= new QAction(i18n("Copy Message to Folder"), this);
3431 actionCollection()->addAction(QStringLiteral("copy_message_to_folder"), action
);
3432 connect(action
, &QAction::triggered
,
3433 this, &KMMainWidget::slotCopySelectedMessagesToFolder
);
3434 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::Key_C
));
3437 QAction
*action
= new QAction(i18n("Jump to Folder..."), this);
3438 actionCollection()->addAction(QStringLiteral("jump_to_folder"), action
);
3439 connect(action
, &QAction::triggered
,
3440 this, &KMMainWidget::slotJumpToFolder
);
3441 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::Key_J
));
3444 QAction
*action
= new QAction(i18n("Abort Current Operation"), this);
3445 actionCollection()->addAction(QStringLiteral("cancel"), action
);
3446 connect(action
, &QAction::triggered
,
3447 ProgressManager::instance(), &KPIM::ProgressManager::slotAbortAll
);
3448 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::Key_Escape
));
3451 QAction
*action
= new QAction(i18n("Focus on Next Folder"), this);
3452 actionCollection()->addAction(QStringLiteral("inc_current_folder"), action
);
3453 connect(action
, &QAction::triggered
,
3454 mFolderTreeWidget
->folderTreeView(), &FolderTreeView::slotFocusNextFolder
);
3455 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_Right
));
3458 QAction
*action
= new QAction(i18n("Focus on Previous Folder"), this);
3459 actionCollection()->addAction(QStringLiteral("dec_current_folder"), action
);
3460 connect(action
, &QAction::triggered
,
3461 mFolderTreeWidget
->folderTreeView(), &FolderTreeView::slotFocusPrevFolder
);
3462 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_Left
));
3465 QAction
*action
= new QAction(i18n("Select Folder with Focus"), this);
3466 actionCollection()->addAction(QStringLiteral("select_current_folder"), action
);
3468 connect(action
, &QAction::triggered
,
3469 mFolderTreeWidget
->folderTreeView(), &FolderTreeView::slotSelectFocusFolder
);
3470 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_Space
));
3473 QAction
*action
= new QAction(i18n("Focus on First Folder"), this);
3474 actionCollection()->addAction(QStringLiteral("focus_first_folder"), action
);
3475 connect(action
, &QAction::triggered
,
3476 mFolderTreeWidget
->folderTreeView(), &FolderTreeView::slotFocusFirstFolder
);
3477 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_Home
));
3480 QAction
*action
= new QAction(i18n("Focus on Last Folder"), this);
3481 actionCollection()->addAction(QStringLiteral("focus_last_folder"), action
);
3482 connect(action
, &QAction::triggered
,
3483 mFolderTreeWidget
->folderTreeView(), &FolderTreeView::slotFocusLastFolder
);
3484 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::CTRL
+ Qt::Key_End
));
3487 QAction
*action
= new QAction(i18n("Focus on Next Message"), this);
3488 actionCollection()->addAction(QStringLiteral("inc_current_message"), action
);
3489 connect(action
, &QAction::triggered
,
3490 this, &KMMainWidget::slotFocusOnNextMessage
);
3491 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::ALT
+ Qt::Key_Right
));
3494 QAction
*action
= new QAction(i18n("Focus on Previous Message"), this);
3495 actionCollection()->addAction(QStringLiteral("dec_current_message"), action
);
3496 connect(action
, &QAction::triggered
,
3497 this, &KMMainWidget::slotFocusOnPrevMessage
);
3498 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::ALT
+ Qt::Key_Left
));
3501 QAction
*action
= new QAction(i18n("Select First Message"), this);
3502 actionCollection()->addAction(QStringLiteral("select_first_message"), action
);
3503 connect(action
, &QAction::triggered
,
3504 this, &KMMainWidget::slotSelectFirstMessage
);
3505 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::ALT
+ Qt::Key_Home
));
3508 QAction
*action
= new QAction(i18n("Select Last Message"), this);
3509 actionCollection()->addAction(QStringLiteral("select_last_message"), action
);
3510 connect(action
, &QAction::triggered
,
3511 this, &KMMainWidget::slotSelectLastMessage
);
3512 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::ALT
+ Qt::Key_End
));
3515 QAction
*action
= new QAction(i18n("Select Message with Focus"), this);
3516 actionCollection()->addAction(QStringLiteral("select_current_message"), action
);
3517 connect(action
, &QAction::triggered
,
3518 this, &KMMainWidget::slotSelectFocusedMessage
);
3519 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::ALT
+ Qt::Key_Space
));
3523 mQuickSearchAction
= new QAction(i18n("Set Focus to Quick Search"), this);
3524 //If change shortcut change Panel::setQuickSearchClickMessage(...) message
3525 actionCollection()->setDefaultShortcut(mQuickSearchAction
, QKeySequence(Qt::ALT
+ Qt::Key_Q
));
3526 actionCollection()->addAction(QStringLiteral("focus_to_quickseach"), mQuickSearchAction
);
3527 connect(mQuickSearchAction
, &QAction::triggered
,
3528 this, &KMMainWidget::slotFocusQuickSearch
);
3529 updateQuickSearchLineText();
3532 QAction
*action
= new QAction(i18n("Extend Selection to Previous Message"), this);
3533 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::SHIFT
+ Qt::Key_Left
));
3534 actionCollection()->addAction(QStringLiteral("previous_message"), action
);
3535 connect(action
, &QAction::triggered
,
3536 this, &KMMainWidget::slotExtendSelectionToPreviousMessage
);
3539 QAction
*action
= new QAction(i18n("Extend Selection to Next Message"), this);
3540 actionCollection()->setDefaultShortcut(action
, QKeySequence(Qt::SHIFT
+ Qt::Key_Right
));
3541 actionCollection()->addAction(QStringLiteral("next_message"), action
);
3542 connect(action
, &QAction::triggered
,
3543 this, &KMMainWidget::slotExtendSelectionToNextMessage
);
3547 mMoveMsgToFolderAction
= new QAction(i18n("Move Message to Folder"), this);
3548 actionCollection()->setDefaultShortcut(mMoveMsgToFolderAction
, QKeySequence(Qt::Key_M
));
3549 actionCollection()->addAction(QStringLiteral("move_message_to_folder"), mMoveMsgToFolderAction
);
3550 connect(mMoveMsgToFolderAction
, &QAction::triggered
,
3551 this, &KMMainWidget::slotMoveSelectedMessageToFolder
);
3554 mArchiveAction
= new QAction(i18nc("@action", "Archive"), this);
3555 actionCollection()->addAction(QStringLiteral("archive_mails"), mArchiveAction
);
3556 connect(mArchiveAction
, &QAction::triggered
, this, &KMMainWidget::slotArchiveMails
);
3558 mLowBandwithAction
= new KToggleAction(i18n("Low Bandwidth"), this);
3559 actionCollection()->addAction(QStringLiteral("low_bandwidth"), mLowBandwithAction
);
3560 connect(mLowBandwithAction
, &KToggleAction::triggered
, this, &KMMainWidget::slotBandwidth
);
3562 mMarkAllMessageAsReadAndInAllSubFolder
= new QAction(i18n("Mark All Messages As Read in This Folder and All its Subfolder"), this);
3563 mMarkAllMessageAsReadAndInAllSubFolder
->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-read")));
3564 actionCollection()->addAction(QStringLiteral("markallmessagereadcurentfolderandsubfolder"), mMarkAllMessageAsReadAndInAllSubFolder
);
3565 connect(mMarkAllMessageAsReadAndInAllSubFolder
, &KToggleAction::triggered
, this, &KMMainWidget::slotMarkAllMessageAsReadInCurrentFolderAndSubfolder
);
3569 void KMMainWidget::slotAddFavoriteFolder()
3571 if (!mFavoritesModel
) {
3574 QPointer
<MailCommon::FolderSelectionDialog
> dialog(selectFromAllFoldersDialog());
3575 dialog
->setWindowTitle(i18n("Add Favorite Folder"));
3576 if (dialog
->exec() && dialog
) {
3577 const Akonadi::Collection collection
= dialog
->selectedCollection();
3578 if (collection
.isValid()) {
3579 mFavoritesModel
->addCollection(collection
);
3584 //-----------------------------------------------------------------------------
3585 void KMMainWidget::slotEditNotifications()
3587 KMail::KMKnotify
notifyDlg(this);
3591 //-----------------------------------------------------------------------------
3592 void KMMainWidget::slotReadOn()
3597 if (!mMsgView
->viewer()->atBottom()) {
3598 mMsgView
->viewer()->slotJumpDown();
3601 slotSelectNextUnreadMessage();
3604 void KMMainWidget::slotNextUnreadFolder()
3606 if (!mFolderTreeWidget
) {
3609 mGoToFirstUnreadMessageInSelectedFolder
= true;
3610 mFolderTreeWidget
->folderTreeView()->selectNextUnreadFolder();
3611 mGoToFirstUnreadMessageInSelectedFolder
= false;
3614 void KMMainWidget::slotPrevUnreadFolder()
3616 if (!mFolderTreeWidget
) {
3619 mGoToFirstUnreadMessageInSelectedFolder
= true;
3620 mFolderTreeWidget
->folderTreeView()->selectPrevUnreadFolder();
3621 mGoToFirstUnreadMessageInSelectedFolder
= false;
3624 void KMMainWidget::slotExpandThread()
3626 mMessagePane
->setCurrentThreadExpanded(true);
3629 void KMMainWidget::slotCollapseThread()
3631 mMessagePane
->setCurrentThreadExpanded(false);
3634 void KMMainWidget::slotExpandAllThreads()
3636 // TODO: Make this asynchronous ? (if there is enough demand)
3637 #ifndef QT_NO_CURSOR
3638 KPIM::KCursorSaver
busy(KPIM::KBusyPtr::busy());
3640 mMessagePane
->setAllThreadsExpanded(true);
3643 void KMMainWidget::slotCollapseAllThreads()
3645 // TODO: Make this asynchronous ? (if there is enough demand)
3646 #ifndef QT_NO_CURSOR
3647 KPIM::KCursorSaver
busy(KPIM::KBusyPtr::busy());
3649 mMessagePane
->setAllThreadsExpanded(false);
3652 //-----------------------------------------------------------------------------
3653 void KMMainWidget::updateMessageMenu()
3655 updateMessageActions();
3658 void KMMainWidget::startUpdateMessageActionsTimer()
3660 // FIXME: This delay effectively CAN make the actions to be in an incoherent state
3661 // Maybe we should mark actions as "dirty" here and check it in every action handler...
3662 updateMessageActions(true);
3665 menutimer
->start(500);
3668 void KMMainWidget::updateMessageActions(bool fast
)
3670 Akonadi::Item::List selectedItems
;
3671 Akonadi::Item::List selectedVisibleItems
;
3672 bool allSelectedBelongToSameThread
= false;
3673 if (mCurrentFolder
&& mCurrentFolder
->isValid() &&
3674 mMessagePane
->getSelectionStats(selectedItems
, selectedVisibleItems
, &allSelectedBelongToSameThread
)
3676 mMsgActions
->setCurrentMessage(mMessagePane
->currentItem(), selectedVisibleItems
);
3678 mMsgActions
->setCurrentMessage(Akonadi::Item());
3682 updateMessageActionsDelayed();
3687 void KMMainWidget::updateMessageActionsDelayed()
3690 Akonadi::Item::List selectedItems
;
3691 Akonadi::Item::List selectedVisibleItems
;
3692 bool allSelectedBelongToSameThread
= false;
3693 Akonadi::Item currentMessage
;
3694 if (mCurrentFolder
&& mCurrentFolder
->isValid() &&
3695 mMessagePane
->getSelectionStats(selectedItems
, selectedVisibleItems
, &allSelectedBelongToSameThread
)
3697 count
= selectedItems
.count();
3699 currentMessage
= mMessagePane
->currentItem();
3703 currentMessage
= Akonadi::Item();
3706 mApplyFiltersOnFolder
->setEnabled(mCurrentFolder
&& mCurrentFolder
->isValid());
3711 // - A list of selected messages stored in selectedSernums.
3712 // The selected messages might contain some invisible ones as a selected
3713 // collapsed node "includes" all the children in the selection.
3714 // - A list of selected AND visible messages stored in selectedVisibleSernums.
3715 // This list does not contain children of selected and collapsed nodes.
3717 // Now, actions can operate on:
3718 // - Any set of messages
3719 // These are called "mass actions" and are enabled whenever we have a message selected.
3720 // In fact we should differentiate between actions that operate on visible selection
3721 // and those that operate on the selection as a whole (without considering visibility)...
3722 // - A single thread
3723 // These are called "thread actions" and are enabled whenever all the selected messages belong
3724 // to the same thread. If the selection doesn't cover the whole thread then the action
3725 // will act on the whole thread anyway (thus will silently extend the selection)
3726 // - A single message
3727 // And we have two sub-cases:
3728 // - The selection must contain exactly one message
3729 // These actions can't ignore the hidden messages and thus must be disabled if
3730 // the selection contains any.
3731 // - The selection must contain exactly one visible message
3732 // These actions will ignore the hidden message and thus can be enabled if
3733 // the selection contains any.
3736 bool readOnly
= mCurrentFolder
&& mCurrentFolder
->isValid() && (mCurrentFolder
->rights() & Akonadi::Collection::ReadOnly
);
3737 // can we apply strictly single message actions ? (this is false if the whole selection contains more than one message)
3738 bool single_actions
= count
== 1;
3739 // can we apply loosely single message actions ? (this is false if the VISIBLE selection contains more than one message)
3740 bool singleVisibleMessageSelected
= selectedVisibleItems
.count() == 1;
3741 // can we apply "mass" actions to the selection ? (this is actually always true if the selection is non-empty)
3742 bool mass_actions
= count
>= 1;
3743 // does the selection identify a single thread ?
3744 bool thread_actions
= mass_actions
&& allSelectedBelongToSameThread
&& mMessagePane
->isThreaded();
3745 // can we apply flags to the selected messages ?
3746 bool flags_available
= KMailSettings::self()->allowLocalFlags() || !(mCurrentFolder
&& mCurrentFolder
->isValid() ? readOnly
: true);
3748 mThreadStatusMenu
->setEnabled(thread_actions
);
3749 // these need to be handled individually, the user might have them
3751 mWatchThreadAction
->setEnabled(thread_actions
&& flags_available
);
3752 mIgnoreThreadAction
->setEnabled(thread_actions
&& flags_available
);
3753 mMarkThreadAsReadAction
->setEnabled(thread_actions
);
3754 mMarkThreadAsUnreadAction
->setEnabled(thread_actions
);
3755 mToggleThreadToActAction
->setEnabled(thread_actions
&& flags_available
);
3756 mToggleThreadImportantAction
->setEnabled(thread_actions
&& flags_available
);
3757 bool canDeleteMessages
= mCurrentFolder
&& mCurrentFolder
->isValid() && (mCurrentFolder
->rights() & Akonadi::Collection::CanDeleteItem
);
3759 mTrashThreadAction
->setEnabled(thread_actions
&& canDeleteMessages
);
3760 mDeleteThreadAction
->setEnabled(thread_actions
&& canDeleteMessages
);
3762 if (currentMessage
.isValid()) {
3763 MessageStatus status
;
3764 status
.setStatusFromFlags(currentMessage
.flags());
3765 mTagActionManager
->updateActionStates(count
, mMessagePane
->currentItem());
3766 if (thread_actions
) {
3767 mToggleThreadToActAction
->setChecked(status
.isToAct());
3768 mToggleThreadImportantAction
->setChecked(status
.isImportant());
3769 mWatchThreadAction
->setChecked(status
.isWatched());
3770 mIgnoreThreadAction
->setChecked(status
.isIgnored());
3774 mMoveActionMenu
->setEnabled(mass_actions
&& canDeleteMessages
);
3775 if (mMoveMsgToFolderAction
) {
3776 mMoveMsgToFolderAction
->setEnabled(mass_actions
&& canDeleteMessages
);
3778 //mCopyActionMenu->setEnabled( mass_actions );
3780 mDeleteAction
->setEnabled(mass_actions
&& canDeleteMessages
);
3782 mExpireConfigAction
->setEnabled(canDeleteMessages
);
3785 mMsgView
->findInMessageAction()->setEnabled(mass_actions
&& !CommonKernel
->folderIsTemplates(mCurrentFolder
->collection()));
3787 mMsgActions
->forwardInlineAction()->setEnabled(mass_actions
&& !CommonKernel
->folderIsTemplates(mCurrentFolder
->collection()));
3788 mMsgActions
->forwardAttachedAction()->setEnabled(mass_actions
&& !CommonKernel
->folderIsTemplates(mCurrentFolder
->collection()));
3789 mMsgActions
->forwardMenu()->setEnabled(mass_actions
&& !CommonKernel
->folderIsTemplates(mCurrentFolder
->collection()));
3791 mMsgActions
->editAction()->setEnabled(single_actions
);
3792 mUseAction
->setEnabled(single_actions
&& CommonKernel
->folderIsTemplates(mCurrentFolder
->collection()));
3793 filterMenu()->setEnabled(single_actions
);
3794 mMsgActions
->redirectAction()->setEnabled(/*single_actions &&*/mass_actions
&& !CommonKernel
->folderIsTemplates(mCurrentFolder
->collection()));
3796 if (mMsgActions
->customTemplatesMenu()) {
3797 mMsgActions
->customTemplatesMenu()->forwardActionMenu()->setEnabled(mass_actions
);
3798 mMsgActions
->customTemplatesMenu()->replyActionMenu()->setEnabled(single_actions
);
3799 mMsgActions
->customTemplatesMenu()->replyAllActionMenu()->setEnabled(single_actions
);
3802 // "Print" will act on the current message: it will ignore any hidden selection
3803 mMsgActions
->printAction()->setEnabled(singleVisibleMessageSelected
);
3804 // "Print preview" will act on the current message: it will ignore any hidden selection
3805 QAction
*printPreviewAction
= mMsgActions
->printPreviewAction();
3806 if (printPreviewAction
) {
3807 printPreviewAction
->setEnabled(singleVisibleMessageSelected
);
3810 // "View Source" will act on the current message: it will ignore any hidden selection
3812 mMsgView
->viewSourceAction()->setEnabled(singleVisibleMessageSelected
);
3814 MessageStatus status
;
3815 status
.setStatusFromFlags(currentMessage
.flags());
3817 QList
< QAction
*> actionList
;
3818 bool statusSendAgain
= single_actions
&& ((currentMessage
.isValid() && status
.isSent()) || (currentMessage
.isValid() && CommonKernel
->folderIsSentMailFolder(mCurrentFolder
->collection())));
3819 if (statusSendAgain
) {
3820 actionList
<< mSendAgainAction
;
3821 } else if (single_actions
) {
3822 actionList
<< messageActions()->editAction();
3824 actionList
<< mSaveAttachmentsAction
;
3825 if (mCurrentFolder
&& FolderArchive::FolderArchiveUtil::resourceSupportArchiving(mCurrentFolder
->collection().resource())) {
3826 actionList
<< mArchiveAction
;
3828 mGUIClient
->unplugActionList(QStringLiteral("messagelist_actionlist"));
3829 mGUIClient
->plugActionList(QStringLiteral("messagelist_actionlist"), actionList
);
3830 mSendAgainAction
->setEnabled(statusSendAgain
);
3832 mSaveAsAction
->setEnabled(mass_actions
);
3834 if ((mCurrentFolder
&& mCurrentFolder
->isValid())) {
3835 updateMoveAction(mCurrentFolder
->statistics());
3837 updateMoveAction(false, false);
3840 const qint64 nbMsgOutboxCollection
= MailCommon::Util::updatedCollection(CommonKernel
->outboxCollectionFolder()).statistics().count();
3842 mSendQueued
->setEnabled(nbMsgOutboxCollection
> 0);
3843 mSendActionMenu
->setEnabled(nbMsgOutboxCollection
> 0);
3845 const bool newPostToMailingList
= mCurrentFolder
&& mCurrentFolder
->isMailingListEnabled();
3846 mMessageNewList
->setEnabled(newPostToMailingList
);
3848 slotUpdateOnlineStatus(static_cast<GlobalSettingsBase::EnumNetworkState::type
>(KMailSettings::self()->networkState()));
3849 if (action(QStringLiteral("kmail_undo"))) {
3850 action(QStringLiteral("kmail_undo"))->setEnabled(kmkernel
->undoStack()->size() > 0);
3853 // Enable / disable all filters.
3854 foreach (QAction
*filterAction
, mFilterMenuActions
) {
3855 filterAction
->setEnabled(count
> 0);
3858 mApplyAllFiltersAction
->setEnabled(count
);
3859 mApplyFilterActionsMenu
->setEnabled(count
);
3862 void KMMainWidget::slotAkonadiStandardActionUpdated()
3864 bool multiFolder
= false;
3865 if (mFolderTreeWidget
) {
3866 multiFolder
= mFolderTreeWidget
->selectedCollections().count() > 1;
3868 if (mCollectionProperties
) {
3869 if (mCurrentFolder
&& mCurrentFolder
->collection().isValid()) {
3870 const Akonadi::AgentInstance instance
=
3871 Akonadi::AgentManager::self()->instance(mCurrentFolder
->collection().resource());
3873 mCollectionProperties
->setEnabled(!multiFolder
&&
3874 !mCurrentFolder
->isStructural() &&
3875 (instance
.status() != Akonadi::AgentInstance::Broken
));
3877 mCollectionProperties
->setEnabled(false);
3879 QList
< QAction
* > collectionProperties
;
3880 if (mCollectionProperties
->isEnabled()) {
3881 collectionProperties
<< mCollectionProperties
;
3883 mGUIClient
->unplugActionList(QStringLiteral("akonadi_collection_collectionproperties_actionlist"));
3884 mGUIClient
->plugActionList(QStringLiteral("akonadi_collection_collectionproperties_actionlist"), collectionProperties
);
3888 const bool folderWithContent
= mCurrentFolder
&& !mCurrentFolder
->isStructural();
3890 if (mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::DeleteCollections
)) {
3892 mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::DeleteCollections
)->setEnabled(mCurrentFolder
3894 && (mCurrentFolder
->collection().rights() & Collection::CanDeleteCollection
)
3895 && !mCurrentFolder
->isSystemFolder()
3896 && folderWithContent
);
3899 if (mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MoveAllToTrash
)) {
3900 mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MoveAllToTrash
)->setEnabled(folderWithContent
3901 && (mCurrentFolder
->count() > 0)
3902 && mCurrentFolder
->canDeleteMessages()
3904 mAkonadiStandardActionManager
->action(Akonadi::StandardMailActionManager::MoveAllToTrash
)->setText((mCurrentFolder
&& CommonKernel
->folderIsTrash(mCurrentFolder
->collection())) ? i18n("E&mpty Trash") : i18n("&Move All Messages to Trash"));
3907 QList
< QAction
* > addToFavorite
;
3908 QAction
*actionAddToFavoriteCollections
= akonadiStandardAction(Akonadi::StandardActionManager::AddToFavoriteCollections
);
3909 if (actionAddToFavoriteCollections
) {
3910 if (mEnableFavoriteFolderView
&& actionAddToFavoriteCollections
->isEnabled()) {
3911 addToFavorite
<< actionAddToFavoriteCollections
;
3913 mGUIClient
->unplugActionList(QStringLiteral("akonadi_collection_add_to_favorites_actionlist"));
3914 mGUIClient
->plugActionList(QStringLiteral("akonadi_collection_add_to_favorites_actionlist"), addToFavorite
);
3917 QList
< QAction
* > syncActionList
;
3918 QAction
*actionSync
= akonadiStandardAction(Akonadi::StandardActionManager::SynchronizeCollections
);
3919 if (actionSync
&& actionSync
->isEnabled()) {
3920 syncActionList
<< actionSync
;
3922 actionSync
= akonadiStandardAction(Akonadi::StandardActionManager::SynchronizeCollectionsRecursive
);
3923 if (actionSync
&& actionSync
->isEnabled()) {
3924 syncActionList
<< actionSync
;
3926 mGUIClient
->unplugActionList(QStringLiteral("akonadi_collection_sync_actionlist"));
3927 mGUIClient
->plugActionList(QStringLiteral("akonadi_collection_sync_actionlist"), syncActionList
);
3929 QList
< QAction
* > actionList
;
3931 QAction
*action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CreateCollection
);
3932 if (action
&& action
->isEnabled()) {
3933 actionList
<< action
;
3936 action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::MoveCollectionToMenu
);
3937 if (action
&& action
->isEnabled()) {
3938 actionList
<< action
;
3941 action
= mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::CopyCollectionToMenu
);
3942 if (action
&& action
->isEnabled()) {
3943 actionList
<< action
;
3945 mGUIClient
->unplugActionList(QStringLiteral("akonadi_collection_move_copy_menu_actionlist"));
3946 mGUIClient
->plugActionList(QStringLiteral("akonadi_collection_move_copy_menu_actionlist"), actionList
);
3950 void KMMainWidget::updateHtmlMenuEntry()
3952 if (mDisplayMessageFormatMenu
&& mPreferHtmlLoadExtAction
) {
3953 bool multiFolder
= false;
3954 if (mFolderTreeWidget
) {
3955 multiFolder
= mFolderTreeWidget
->selectedCollections().count() > 1;
3957 // the visual ones only make sense if we are showing a message list
3958 const bool enabledAction
= (mFolderTreeWidget
&&
3959 mFolderTreeWidget
->folderTreeView()->currentFolder().isValid() &&
3962 mDisplayMessageFormatMenu
->setEnabled(enabledAction
);
3963 const bool isEnabled
= (mFolderTreeWidget
&&
3964 mFolderTreeWidget
->folderTreeView()->currentFolder().isValid() &&
3966 const bool useHtml
= (mFolderDisplayFormatPreference
== MessageViewer::Viewer::Html
|| (mHtmlGlobalSetting
&& mFolderDisplayFormatPreference
== MessageViewer::Viewer::UseGlobalSetting
));
3967 mPreferHtmlLoadExtAction
->setEnabled(isEnabled
&& useHtml
);
3969 mDisplayMessageFormatMenu
->setDisplayMessageFormat(mFolderDisplayFormatPreference
);
3971 mPreferHtmlLoadExtAction
->setChecked(!multiFolder
&& (mHtmlLoadExtGlobalSetting
? !mFolderHtmlLoadExtPreference
: mFolderHtmlLoadExtPreference
));
3975 //-----------------------------------------------------------------------------
3976 void KMMainWidget::updateFolderMenu()
3978 if (!CommonKernel
->outboxCollectionFolder().isValid()) {
3979 QTimer::singleShot(1000, this, &KMMainWidget::updateFolderMenu
);
3983 const bool folderWithContent
= mCurrentFolder
&& !mCurrentFolder
->isStructural();
3984 bool multiFolder
= false;
3985 if (mFolderTreeWidget
) {
3986 multiFolder
= mFolderTreeWidget
->selectedCollections().count() > 1;
3988 mFolderMailingListPropertiesAction
->setEnabled(folderWithContent
&&
3990 !mCurrentFolder
->isSystemFolder());
3992 QList
< QAction
* > actionlist
;
3993 if (mCurrentFolder
&& mCurrentFolder
->collection().id() == CommonKernel
->outboxCollectionFolder().id() && (mCurrentFolder
->collection()).statistics().count() > 0) {
3994 qCDebug(KMAIL_LOG
) << "Enabling send queued";
3995 mSendQueued
->setEnabled(true);
3996 actionlist
<< mSendQueued
;
3998 // if ( mCurrentFolder && mCurrentFolder->collection().id() != CommonKernel->trashCollectionFolder().id() ) {
3999 // actionlist << mTrashAction;
4001 mGUIClient
->unplugActionList(QStringLiteral("outbox_folder_actionlist"));
4002 mGUIClient
->plugActionList(QStringLiteral("outbox_folder_actionlist"), actionlist
);
4005 const bool isASearchFolder
= mCurrentFolder
&& mCurrentFolder
->collection().resource() == QLatin1String("akonadi_search_resource");
4006 if (isASearchFolder
) {
4007 mAkonadiStandardActionManager
->action(Akonadi::StandardActionManager::DeleteCollections
)->setText(i18n("&Delete Search"));
4010 mArchiveFolderAction
->setEnabled(mCurrentFolder
&& !multiFolder
&& folderWithContent
);
4012 bool isInTrashFolder
= (mCurrentFolder
&& CommonKernel
->folderIsTrash(mCurrentFolder
->collection()));
4013 QAction
*moveToTrash
= akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash
);
4014 akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash
)->setText(isInTrashFolder
? i18nc("@action Hard delete, bypassing trash", "&Delete") : i18n("&Move to Trash"));
4015 akonadiStandardAction(Akonadi::StandardMailActionManager::MoveToTrash
)->setIcon(isInTrashFolder
? QIcon::fromTheme(QStringLiteral("edit-delete")) : QIcon::fromTheme(QStringLiteral("user-trash")));
4016 //Use same text as in Text property. Change it in kf5
4017 moveToTrash
->setToolTip(isInTrashFolder
? i18nc("@action Hard delete, bypassing trash", "&Delete") : i18n("&Move to Trash"));
4019 mTrashThreadAction
->setIcon(isInTrashFolder
? QIcon::fromTheme(QStringLiteral("edit-delete")) : QIcon::fromTheme(QStringLiteral("user-trash")));
4020 mTrashThreadAction
->setText(isInTrashFolder
? i18n("Delete T&hread") : i18n("M&ove Thread to Trash"));
4022 mSearchMessages
->setText((mCurrentFolder
&& mCurrentFolder
->collection().resource() == QLatin1String("akonadi_search_resource")) ? i18n("Edit Search...") : i18n("&Find Messages..."));
4024 mExpireConfigAction
->setEnabled(mCurrentFolder
&&
4025 !mCurrentFolder
->isStructural() &&
4027 mCurrentFolder
->canDeleteMessages() &&
4028 folderWithContent
&&
4029 !MailCommon::Util::isVirtualCollection(mCurrentFolder
->collection()));
4031 updateHtmlMenuEntry();
4033 mShowFolderShortcutDialogAction
->setEnabled(!multiFolder
&& folderWithContent
);
4035 actionlist
<< akonadiStandardAction(Akonadi::StandardActionManager::ManageLocalSubscriptions
);
4036 bool imapFolderIsOnline
= false;
4037 if (mCurrentFolder
&& PimCommon::Util::isImapFolder(mCurrentFolder
->collection(), imapFolderIsOnline
)) {
4038 if (imapFolderIsOnline
) {
4039 actionlist
<< mServerSideSubscription
;
4043 mGUIClient
->unplugActionList(QStringLiteral("collectionview_actionlist"));
4044 mGUIClient
->plugActionList(QStringLiteral("collectionview_actionlist"), actionlist
);
4048 //-----------------------------------------------------------------------------
4049 void KMMainWidget::slotIntro()
4055 mMsgView
->clear(true);
4057 // hide widgets that are in the way:
4058 if (mMessagePane
&& mLongFolderList
) {
4059 mMessagePane
->hide();
4061 mMsgView
->displayAboutPage();
4063 mCurrentFolder
.clear();
4066 void KMMainWidget::slotShowStartupFolder()
4068 connect(MailCommon::FilterManager::instance(), &FilterManager::filtersChanged
,
4069 this, &KMMainWidget::initializeFilterActions
);
4070 // Plug various action lists. This can't be done in the constructor, as that is called before
4071 // the main window or Kontact calls createGUI().
4072 // This function however is called with a single shot timer.
4073 checkAkonadiServerManagerState();
4074 mFolderShortcutActionManager
->createActions();
4075 mTagActionManager
->createActions();
4076 messageActions()->setupForwardingActionsList(mGUIClient
);
4078 QString newFeaturesMD5
= KMReaderWin::newFeaturesMD5();
4079 if (kmkernel
->firstStart() ||
4080 KMailSettings::self()->previousNewFeaturesMD5() != newFeaturesMD5
) {
4081 KMailSettings::self()->setPreviousNewFeaturesMD5(newFeaturesMD5
);
4087 void KMMainWidget::checkAkonadiServerManagerState()
4089 Akonadi::ServerManager::State state
= Akonadi::ServerManager::self()->state();
4090 if (state
== Akonadi::ServerManager::Running
) {
4091 initializeFilterActions();
4093 connect(Akonadi::ServerManager::self(), &ServerManager::stateChanged
,
4094 this, &KMMainWidget::slotServerStateChanged
);
4098 void KMMainWidget::slotServerStateChanged(Akonadi::ServerManager::State state
)
4100 if (state
== Akonadi::ServerManager::Running
) {
4101 initializeFilterActions();
4102 disconnect(Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State
)));
4106 QList
<KActionCollection
*> KMMainWidget::actionCollections() const
4108 return QList
<KActionCollection
*>() << actionCollection();
4111 //-----------------------------------------------------------------------------
4112 void KMMainWidget::slotUpdateUndo()
4114 if (actionCollection()->action(QStringLiteral("kmail_undo"))) {
4115 QAction
*act
= actionCollection()->action(QStringLiteral("kmail_undo"));
4116 act
->setEnabled(!kmkernel
->undoStack()->isEmpty());
4117 const QString infoStr
= kmkernel
->undoStack()->undoInfo();
4118 if (infoStr
.isEmpty()) {
4119 act
->setText(i18n("&Undo"));
4121 act
->setText(i18n("&Undo: \"%1\"", kmkernel
->undoStack()->undoInfo()));
4126 //-----------------------------------------------------------------------------
4127 void KMMainWidget::clearFilterActions()
4129 if (!mFilterTBarActions
.isEmpty())
4130 if (mGUIClient
->factory()) {
4131 mGUIClient
->unplugActionList(QStringLiteral("toolbar_filter_actions"));
4134 if (!mFilterMenuActions
.isEmpty())
4135 if (mGUIClient
->factory()) {
4136 mGUIClient
->unplugActionList(QStringLiteral("menu_filter_actions"));
4139 foreach (QAction
*a
, mFilterMenuActions
) {
4140 actionCollection()->removeAction(a
);
4143 mApplyFilterActionsMenu
->menu()->clear();
4144 mFilterTBarActions
.clear();
4145 mFilterMenuActions
.clear();
4147 qDeleteAll(mFilterCommands
);
4148 mFilterCommands
.clear();
4151 //-----------------------------------------------------------------------------
4152 void KMMainWidget::initializeFilterActions()
4154 clearFilterActions();
4155 mApplyFilterActionsMenu
->menu()->addAction(mApplyAllFiltersAction
);
4156 bool addedSeparator
= false;
4158 foreach (MailFilter
*filter
, MailCommon::FilterManager::instance()->filters()) {
4159 if (!filter
->isEmpty() && filter
->configureShortcut() && filter
->isEnabled()) {
4160 QString filterName
= QStringLiteral("Filter %1").arg(filter
->name());
4161 QString normalizedName
= filterName
.replace(QLatin1Char(' '), QLatin1Char('_'));
4162 if (action(normalizedName
)) {
4165 KMMetaFilterActionCommand
*filterCommand
= new KMMetaFilterActionCommand(filter
->identifier(), this);
4166 mFilterCommands
.append(filterCommand
);
4167 QString displayText
= i18n("Filter %1", filter
->name());
4168 QString icon
= filter
->icon();
4169 if (icon
.isEmpty()) {
4170 icon
= QStringLiteral("system-run");
4172 QAction
*filterAction
= new QAction(QIcon::fromTheme(icon
), displayText
, actionCollection());
4173 filterAction
->setIconText(filter
->toolbarName());
4175 // The shortcut configuration is done in the filter dialog.
4176 // The shortcut set in the shortcut dialog would not be saved back to
4177 // the filter settings correctly.
4178 actionCollection()->setShortcutsConfigurable(filterAction
, false);
4179 actionCollection()->addAction(normalizedName
,
4181 connect(filterAction
, &QAction::triggered
,
4182 filterCommand
, &KMMetaFilterActionCommand::start
);
4183 actionCollection()->setDefaultShortcut(filterAction
, filter
->shortcut());
4184 if (!addedSeparator
) {
4185 QAction
*a
= mApplyFilterActionsMenu
->menu()->addSeparator();
4186 mFilterMenuActions
.append(a
);
4187 addedSeparator
= true;
4189 mApplyFilterActionsMenu
->menu()->addAction(filterAction
);
4190 mFilterMenuActions
.append(filterAction
);
4191 if (filter
->configureToolbar()) {
4192 mFilterTBarActions
.append(filterAction
);
4196 if (!mFilterMenuActions
.isEmpty() && mGUIClient
->factory()) {
4197 mGUIClient
->plugActionList(QStringLiteral("menu_filter_actions"), mFilterMenuActions
);
4199 if (!mFilterTBarActions
.isEmpty() && mGUIClient
->factory()) {
4200 mFilterTBarActions
.prepend(mToolbarActionSeparator
);
4201 mGUIClient
->plugActionList(QStringLiteral("toolbar_filter_actions"), mFilterTBarActions
);
4204 // Our filters have changed, now enable/disable them
4205 updateMessageActions();
4208 void KMMainWidget::updateFileMenu()
4210 const bool isEmpty
= MailCommon::Util::agentInstances().isEmpty();
4211 actionCollection()->action(QStringLiteral("check_mail"))->setEnabled(!isEmpty
);
4212 actionCollection()->action(QStringLiteral("check_mail_in"))->setEnabled(!isEmpty
);
4215 //-----------------------------------------------------------------------------
4216 const KMMainWidget::PtrList
*KMMainWidget::mainWidgetList()
4218 // better safe than sorry; check whether the global static has already been destroyed
4219 if (theMainWidgetList
.isDestroyed()) {
4222 return theMainWidgetList
;
4225 QSharedPointer
<FolderCollection
> KMMainWidget::currentFolder() const
4227 return mCurrentFolder
;
4230 //-----------------------------------------------------------------------------
4231 QString
KMMainWidget::overrideEncoding() const
4234 return mMsgView
->overrideEncoding();
4236 return MessageCore::MessageCoreSettings::self()->overrideCharacterEncoding();
4240 void KMMainWidget::showEvent(QShowEvent
*event
)
4242 QWidget::showEvent(event
);
4243 mWasEverShown
= true;
4246 void KMMainWidget::slotRequestFullSearchFromQuickSearch()
4248 // First, open the search window. If we are currently on a search folder,
4249 // the search associated with that will be loaded.
4250 if (!slotSearch()) {
4256 // Now we look at the current state of the quick search, and if there's
4257 // something in there, we add the criteria to the existing search for
4258 // the search folder, if applicable, or make a new one from it.
4259 SearchPattern pattern
;
4260 const QString searchString
= mMessagePane
->currentFilterSearchString();
4261 if (!searchString
.isEmpty()) {
4262 MessageList::Core::QuickSearchLine::SearchOptions options
= mMessagePane
->currentOptions();
4263 QByteArray searchStringVal
;
4264 if (options
& MessageList::Core::QuickSearchLine::SearchEveryWhere
) {
4265 searchStringVal
= "<message>";
4266 } else if (options
& MessageList::Core::QuickSearchLine::SearchAgainstSubject
) {
4267 searchStringVal
= "subject";
4268 } else if (options
& MessageList::Core::QuickSearchLine::SearchAgainstBody
) {
4269 searchStringVal
= "<body>";
4270 } else if (options
& MessageList::Core::QuickSearchLine::SearchAgainstFrom
) {
4271 searchStringVal
= "from";
4272 } else if (options
& MessageList::Core::QuickSearchLine::SearchAgainstBcc
) {
4273 searchStringVal
= "bcc";
4274 } else if (options
& MessageList::Core::QuickSearchLine::SearchAgainstTo
) {
4275 searchStringVal
= "to";
4277 searchStringVal
= "<message>";
4279 pattern
.append(SearchRule::createInstance(searchStringVal
, SearchRule::FuncContains
, searchString
));
4280 QList
<MessageStatus
> statusList
= mMessagePane
->currentFilterStatus();
4281 Q_FOREACH (MessageStatus status
, statusList
) {
4282 if (status
.hasAttachment()) {
4283 pattern
.append(SearchRule::createInstance(searchStringVal
, SearchRule::FuncHasAttachment
, searchString
));
4284 status
.setHasAttachment(false);
4286 if (!status
.isOfUnknownStatus()) {
4287 pattern
.append(SearchRule::Ptr(new SearchRuleStatus(status
)));
4291 if (!pattern
.isEmpty()) {
4292 mSearchWin
->addRulesToSearchPattern(pattern
);
4296 void KMMainWidget::updateVacationScriptStatus(bool active
, const QString
&serverName
)
4298 mVacationScriptIndicator
->setVacationScriptActive(active
, serverName
);
4299 mVacationIndicatorActive
= mVacationScriptIndicator
->hasVacationScriptActive();
4302 QWidget
*KMMainWidget::vacationScriptIndicator() const
4304 return mVacationScriptIndicator
;
4307 void KMMainWidget::updateVacationScriptStatus()
4309 updateVacationScriptStatus(mVacationIndicatorActive
);
4312 KMail::TagActionManager
*KMMainWidget::tagActionManager() const
4314 return mTagActionManager
;
4317 KMail::FolderShortcutActionManager
*KMMainWidget::folderShortcutActionManager() const
4319 return mFolderShortcutActionManager
;
4322 void KMMainWidget::slotMessageSelected(const Akonadi::Item
&item
)
4324 delete mShowBusySplashTimer
;
4325 mShowBusySplashTimer
= Q_NULLPTR
;
4327 // The current selection was cleared, so we'll remove the previously
4328 // selected message from the preview pane
4329 if (!item
.isValid()) {
4332 mShowBusySplashTimer
= new QTimer(this);
4333 mShowBusySplashTimer
->setSingleShot(true);
4334 connect(mShowBusySplashTimer
, &QTimer::timeout
, this, &KMMainWidget::slotShowBusySplash
);
4335 mShowBusySplashTimer
->start(1000);
4337 Akonadi::ItemFetchJob
*itemFetchJob
= MessageViewer::Viewer::createFetchJob(item
);
4338 if (mCurrentFolder
) {
4339 const QString resource
= mCurrentFolder
->collection().resource();
4340 itemFetchJob
->setProperty("_resource", QVariant::fromValue(resource
));
4341 connect(itemFetchJob
, &ItemFetchJob::itemsReceived
,
4342 this, &KMMainWidget::itemsReceived
);
4343 connect(itemFetchJob
, &Akonadi::ItemFetchJob::result
, this, &KMMainWidget::itemsFetchDone
);
4349 void KMMainWidget::itemsReceived(const Akonadi::Item::List
&list
)
4351 Q_ASSERT(list
.size() == 1);
4352 delete mShowBusySplashTimer
;
4353 mShowBusySplashTimer
= Q_NULLPTR
;
4359 Item item
= list
.first();
4362 mMessagePane
->show();
4364 if (mMessagePane
->currentItem() != item
) {
4365 // The user has selected another email already, so don't render this one.
4366 // Mark it as read, though, if the user settings say so.
4367 if (MessageViewer::MessageViewerSettings::self()->delayedMarkAsRead() &&
4368 MessageViewer::MessageViewerSettings::self()->delayedMarkTime() == 0) {
4369 item
.setFlag(Akonadi::MessageFlags::Seen
);
4370 Akonadi::ItemModifyJob
*modifyJob
= new Akonadi::ItemModifyJob(item
, this);
4371 modifyJob
->disableRevisionCheck();
4372 modifyJob
->setIgnorePayload(true);
4378 mMsgView
->setMessage(item
);
4379 // reset HTML Q_DECL_OVERRIDE to the folder setting
4380 mMsgView
->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference
);
4381 mMsgView
->setHtmlLoadExtOverride(mFolderHtmlLoadExtPreference
);
4382 mMsgView
->setDecryptMessageOverwrite(false);
4383 mMsgActions
->setCurrentMessage(item
);
4386 void KMMainWidget::itemsFetchDone(KJob
*job
)
4388 delete mShowBusySplashTimer
;
4389 mShowBusySplashTimer
= Q_NULLPTR
;
4391 // Unfortunately job->error() is Job::Unknown in many cases.
4392 // (see JobPrivate::handleResponse in akonadi/job.cpp)
4393 // So we show the "offline" page after checking the resource status.
4394 qCDebug(KMAIL_LOG
) << job
->error() << job
->errorString();
4396 const QString resource
= job
->property("_resource").toString();
4397 const Akonadi::AgentInstance agentInstance
= Akonadi::AgentManager::self()->instance(resource
);
4398 if (!agentInstance
.isOnline()) {
4399 // The resource is offline
4401 mMsgView
->viewer()->enableMessageDisplay();
4402 mMsgView
->clear(true);
4404 mMessagePane
->show();
4406 if (kmkernel
->isOffline()) {
4410 showResourceOfflinePage();
4415 BroadcastStatus::instance()->setStatusMsg(job
->errorString());
4420 QAction
*KMMainWidget::akonadiStandardAction(Akonadi::StandardActionManager::Type type
)
4422 return mAkonadiStandardActionManager
->action(type
);
4425 QAction
*KMMainWidget::akonadiStandardAction(Akonadi::StandardMailActionManager::Type type
)
4427 return mAkonadiStandardActionManager
->action(type
);
4430 void KMMainWidget::slotRemoveDuplicates()
4432 RemoveDuplicateMailJob
*job
= new RemoveDuplicateMailJob(mFolderTreeWidget
->folderTreeView()->selectionModel(), this, this);
4436 void KMMainWidget::slotServerSideSubscription()
4438 if (!mCurrentFolder
) {
4441 PimCommon::ManageServerSideSubscriptionJob
*job
= new PimCommon::ManageServerSideSubscriptionJob(this);
4442 job
->setCurrentCollection(mCurrentFolder
->collection());
4443 job
->setParentWidget(this);
4447 void KMMainWidget::savePaneSelection()
4450 mMessagePane
->saveCurrentSelection();
4454 void KMMainWidget::updatePaneTagComboBox()
4457 mMessagePane
->updateTagComboBox();
4461 void KMMainWidget::slotCreateAddressBookContact()
4463 CreateNewContactJob
*job
= new CreateNewContactJob(this, this);
4467 void KMMainWidget::slotOpenRecentMsg(const QUrl
&url
)
4469 KMOpenMsgCommand
*openCommand
= new KMOpenMsgCommand(this, url
, overrideEncoding(), this);
4470 openCommand
->start();
4473 void KMMainWidget::addRecentFile(const QUrl
&mUrl
)
4475 mOpenRecentAction
->addUrl(mUrl
);
4476 KConfigGroup grp
= mConfig
->group(QStringLiteral("Recent Files"));
4477 mOpenRecentAction
->saveEntries(grp
);
4481 void KMMainWidget::slotMoveMessageToTrash()
4483 if (messageView() && messageView()->viewer() && mCurrentFolder
) {
4484 KMTrashMsgCommand
*command
= new KMTrashMsgCommand(mCurrentFolder
->collection(), messageView()->viewer()->messageItem(), -1);
4489 void KMMainWidget::slotArchiveMails()
4491 if (mCurrentFolder
&& mCurrentFolder
->collection().isValid()) {
4492 const Akonadi::Item::List selectedMessages
= mMessagePane
->selectionAsMessageItemList();
4493 KMKernel::self()->folderArchiveManager()->setArchiveItems(selectedMessages
, mCurrentFolder
->collection().resource());
4497 void KMMainWidget::updateQuickSearchLineText()
4499 //If change change shortcut
4500 mMessagePane
->setQuickSearchClickMessage(i18nc("Show shortcut for focus quick search. Don't change it", "Search...<%1>", mQuickSearchAction
->shortcut().toString()));
4503 void KMMainWidget::slotChangeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage format
)
4505 if (format
== MessageViewer::Viewer::Html
) {
4506 const int result
= KMessageBox::warningContinueCancel(this,
4507 // the warning text is taken from configuredialog.cpp:
4508 i18n("Use of HTML in mail will make you more vulnerable to "
4509 "\"spam\" and may increase the likelihood that your system will be "
4510 "compromised by other present and anticipated security exploits."),
4511 i18n("Security Warning"),
4512 KGuiItem(i18n("Use HTML")),
4513 KStandardGuiItem::cancel(),
4514 QStringLiteral("OverrideHtmlWarning"), Q_NULLPTR
);
4515 if (result
== KMessageBox::Cancel
) {
4516 mDisplayMessageFormatMenu
->setDisplayMessageFormat(MessageViewer::Viewer::Text
);
4520 mFolderDisplayFormatPreference
= format
;
4522 //Update mPrefererHtmlLoadExtAction
4523 const bool useHtml
= (mFolderDisplayFormatPreference
== MessageViewer::Viewer::Html
|| (mHtmlGlobalSetting
&& mFolderDisplayFormatPreference
== MessageViewer::Viewer::UseGlobalSetting
));
4524 mPreferHtmlLoadExtAction
->setEnabled(useHtml
);
4527 mMsgView
->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference
);
4528 mMsgView
->update(true);
4532 void KMMainWidget::populateMessageListStatusFilterCombo()
4534 mMessagePane
->populateStatusFilterCombo();
4537 void KMMainWidget::slotCollectionRemoved(const Akonadi::Collection
&col
)
4539 if (mFavoritesModel
) {
4540 mFavoritesModel
->removeCollection(col
);
4544 void KMMainWidget::slotMarkAllMessageAsReadInCurrentFolderAndSubfolder()
4546 if (mCurrentFolder
&& mCurrentFolder
->collection().isValid()) {
4547 MarkAllMessagesAsReadInFolderAndSubFolderJob
*job
= new MarkAllMessagesAsReadInFolderAndSubFolderJob(this);
4548 job
->setTopLevelCollection(mCurrentFolder
->collection());