kmmainwidget.cpp 199 KB
Newer Older
Laurent Montel's avatar
Laurent Montel committed
1
/*
2
3
  This file is part of KMail, the KDE mail client.
  Copyright (c) 2002 Don Sanders <sanders@kde.org>
Laurent Montel's avatar
Laurent Montel committed
4
  Copyright (c) 2009-2020 Laurent Montel <montel@kde.org>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

  Based on the work of Stefan Taferner <taferner@kde.org>

  KMail is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License, version 2, as
  published by the Free Software Foundation.

  KMail is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
Stephan Kulow's avatar
Stephan Kulow committed
21

Thomas McGuire's avatar
Thomas McGuire committed
22
// KMail includes
Yuri Chornoivan's avatar
Yuri Chornoivan committed
23
#include "kmmainwidget.h"
Leo Franchi's avatar
Leo Franchi committed
24
#include "kmreadermainwin.h"
25
#include "job/composenewmessagejob.h"
Laurent Montel's avatar
Laurent Montel committed
26
#include "editor/composer.h"
Laurent Montel's avatar
Laurent Montel committed
27
#include "searchdialog/searchwindow.h"
28
#include "widgets/vacationscriptindicatorwidget.h"
Laurent Montel's avatar
Laurent Montel committed
29
#include "widgets/zoomlabelwidget.h"
Thomas McGuire's avatar
Thomas McGuire committed
30
31
32
#include "undostack.h"
#include "kmcommands.h"
#include "kmmainwin.h"
33
#include <TemplateParser/CustomTemplatesMenu>
Laurent Montel's avatar
Laurent Montel committed
34
35
#include "MailCommon/FolderSelectionDialog"
#include "MailCommon/FolderTreeWidget"
Laurent Montel's avatar
Laurent Montel committed
36
#include "PimCommonAkonadi/MailUtil"
Laurent Montel's avatar
Port++    
Laurent Montel committed
37
#include "util.h"
38

Laurent Montel's avatar
Laurent Montel committed
39
40
#include "mailcommon/mailutil.h"
#include "mailcommon/mailkernel.h"
Laurent Montel's avatar
Laurent Montel committed
41
#include "dialog/archivefolderdialog.h"
Laurent Montel's avatar
Laurent Montel committed
42
#include "settings/kmailsettings.h"
Laurent Montel's avatar
Laurent Montel committed
43
#include "MailCommon/FolderTreeView"
Laurent Montel's avatar
Laurent Montel committed
44
#include "tag/tagactionmanager.h"
45
#include "foldershortcutactionmanager.h"
Laurent Montel's avatar
Laurent Montel committed
46
#include "widgets/collectionpane.h"
47
#include "manageshowcollectionproperties.h"
48
#include "widgets/kactionmenutransport.h"
49
#include "widgets/kactionmenuaccount.h"
50
#include "mailcommon/searchrulestatus.h"
Laurent Montel's avatar
Laurent Montel committed
51
#include "plugininterface/kmailplugininterface.h"
Laurent Montel's avatar
Laurent Montel committed
52
#include "kpimtextedit/texttospeech.h"
53
#include "job/markallmessagesasreadinfolderandsubfolderjob.h"
54
#include "job/removeduplicatemessageinfolderandsubfolderjob.h"
55
#include "sieveimapinterface/kmsieveimappasswordprovider.h"
Laurent Montel's avatar
Laurent Montel committed
56
#include <KSieveUi/SieveDebugDialog>
57

58
#include <AkonadiWidgets/CollectionMaintenancePage>
Laurent Montel's avatar
Laurent Montel committed
59
60
61
62
63
#include "collectionpage/collectionquotapage.h"
#include "collectionpage/collectiontemplatespage.h"
#include "collectionpage/collectionshortcutpage.h"
#include "collectionpage/collectionviewpage.h"
#include "collectionpage/collectionmailinglistpage.h"
Laurent Montel's avatar
Laurent Montel committed
64
#include "tag/tagselectdialog.h"
Laurent Montel's avatar
Laurent Montel committed
65
#include "job/createnewcontactjob.h"
66
67
#include "folderarchive/folderarchiveutil.h"
#include "folderarchive/folderarchivemanager.h"
68

Laurent Montel's avatar
Laurent Montel committed
69
#include <PimCommonAkonadi/CollectionAclPage>
Laurent Montel's avatar
Laurent Montel committed
70
#include "PimCommon/PimUtil"
Laurent Montel's avatar
Laurent Montel committed
71
72
73
74
75
76
#include "MailCommon/CollectionGeneralPage"
#include "MailCommon/CollectionExpiryPage"
#include "MailCommon/ExpireCollectionAttribute"
#include "MailCommon/FilterManager"
#include "MailCommon/MailFilter"
#include "MailCommon/FavoriteCollectionWidget"
77
#include "MailCommon/FavoriteCollectionOrderProxyModel"
Laurent Montel's avatar
Laurent Montel committed
78
#include "mailcommonsettings_base.h"
79

Thomas McGuire's avatar
Thomas McGuire committed
80
// Other PIM includes
81
#include "kmail-version.h"
82

83
#include "messageviewer/messageviewersettings.h"
84
#include "messageviewer/viewer.h"
Laurent Montel's avatar
Laurent Montel committed
85
86
#include "messageviewer/headerstyleplugin.h"
#include "messageviewer/headerstyle.h"
Laurent Montel's avatar
Laurent Montel committed
87
#include "messageviewer/config-messageviewer.h"
88

89
#include <MessageViewer/AttachmentStrategy>
90

91
#ifndef QT_NO_CURSOR
92
#include "Libkdepim/KCursorSaver"
93
#endif
94

Laurent Montel's avatar
Laurent Montel committed
95
#include <MessageComposer/MessageSender>
Laurent Montel's avatar
Laurent Montel committed
96
#include "MessageComposer/MessageHelper"
97

Laurent Montel's avatar
Laurent Montel committed
98
#include <MessageCore/MessageCoreSettings>
Laurent Montel's avatar
Laurent Montel committed
99
#include "MessageCore/MailingList"
100

Laurent Montel's avatar
Laurent Montel committed
101
#include "dialog/kmknotify.h"
102
#include "widgets/displaymessageformatactionmenu.h"
103

104
#include "ksieveui/vacationmanager.h"
105
#include "kmlaunchexternalcomponent.h"
Laurent Montel's avatar
Laurent Montel committed
106

Thomas McGuire's avatar
Thomas McGuire committed
107
// LIBKDEPIM includes
Laurent Montel's avatar
Laurent Montel committed
108
#include "libkdepim/progressmanager.h"
Laurent Montel's avatar
Laurent Montel committed
109
#include "libkdepim/broadcaststatus.h"
110

Thomas McGuire's avatar
Thomas McGuire committed
111
// KDEPIMLIBS includes
Laurent Montel's avatar
Laurent Montel committed
112
#include <AkonadiCore/AgentManager>
Laurent Montel's avatar
Laurent Montel committed
113
114
#include <AkonadiCore/AttributeFactory>
#include <AkonadiCore/itemfetchjob.h>
Laurent Montel's avatar
Laurent Montel committed
115
#include <AkonadiCore/collectionattributessynchronizationjob.h>
Laurent Montel's avatar
Laurent Montel committed
116
117
#include <AkonadiCore/collectionfetchjob.h>
#include <AkonadiCore/collectionfetchscope.h>
118
#include <Akonadi/Contact/ContactSearchJob>
Laurent Montel's avatar
Laurent Montel committed
119
#include <AkonadiWidgets/collectionpropertiesdialog.h>
Laurent Montel's avatar
Laurent Montel committed
120
#include <AkonadiCore/entitydisplayattribute.h>
Laurent Montel's avatar
Laurent Montel committed
121
122
#include <AkonadiWidgets/entitylistview.h>
#include <AkonadiWidgets/etmviewstatesaver.h>
Laurent Montel's avatar
Laurent Montel committed
123
124
125
126
127
#include <AkonadiCore/agentinstance.h>
#include <AkonadiCore/agenttype.h>
#include <AkonadiCore/changerecorder.h>
#include <AkonadiCore/session.h>
#include <AkonadiCore/entitytreemodel.h>
Laurent Montel's avatar
Laurent Montel committed
128
#include <AkonadiCore/favoritecollectionsmodel.h>
Laurent Montel's avatar
Laurent Montel committed
129
130
#include <AkonadiCore/itemfetchscope.h>
#include <AkonadiCore/itemmodifyjob.h>
Laurent Montel's avatar
Laurent Montel committed
131
#include <AkonadiWidgets/controlgui.h>
Laurent Montel's avatar
Laurent Montel committed
132
#include <AkonadiWidgets/collectiondialog.h>
Laurent Montel's avatar
Laurent Montel committed
133
#include <AkonadiCore/collectionstatistics.h>
Laurent Montel's avatar
Laurent Montel committed
134
#include <AkonadiCore/EntityMimeTypeFilterModel>
135
#include <Akonadi/KMime/MessageFlags>
Laurent Montel's avatar
Laurent Montel committed
136
#include <AkonadiCore/CachePolicy>
137

Laurent Montel's avatar
Laurent Montel committed
138
139
#include <kidentitymanagement/identity.h>
#include <kidentitymanagement/identitymanager.h>
140
#include <KEmailAddress>
Laurent Montel's avatar
Laurent Montel committed
141
142
143
#include <mailtransport/transportmanager.h>
#include <mailtransport/transport.h>
#include <kmime/kmime_mdn.h>
Laurent Montel's avatar
Laurent Montel committed
144
145
#include <kmime/kmime_header_parsing.h>
#include <kmime/kmime_message.h>
146
147
#include <ksieveui/managesievescriptsdialog.h>
#include <ksieveui/util.h>
148

149
150
#include <PimCommon/LogActivitiesManager>

Thomas McGuire's avatar
Thomas McGuire committed
151
// KDELIBS includes
152
#include <KWindowSystem>
153
154
#include <KMessageBox>
#include <KActionMenu>
Laurent Montel's avatar
Laurent Montel committed
155
#include <QMenu>
156
157
158
#include <KAcceleratorManager>
#include <KStandardShortcut>
#include <KCharsets>
Laurent Montel's avatar
Laurent Montel committed
159
#include "kmail_debug.h"
Laurent Montel's avatar
Laurent Montel committed
160

161
162
163
164
165
166
167
168
169
#include <KStandardAction>
#include <KToggleAction>
#include <KNotification>
#include <KNotifyConfigWidget>
#include <KStringHandler>
#include <KConfigGroup>
#include <KToolInvocation>
#include <KXMLGUIFactory>
#include <KXMLGUIClient>
Laurent Montel's avatar
Laurent Montel committed
170
171
#include <QStatusBar>
#include <QAction>
Laurent Montel's avatar
Laurent Montel committed
172
#include <KRecentFilesAction>
173

Thomas McGuire's avatar
Thomas McGuire committed
174
175
// Qt includes
#include <QByteArray>
176
#include <QHeaderView>
Thomas McGuire's avatar
Thomas McGuire committed
177
178
179
180
181
#include <QList>
#include <QSplitter>
#include <QVBoxLayout>
#include <QShortcut>
#include <QProcess>
182
#include <WebEngineViewer/WebHitTestResult>
Thomas McGuire's avatar
Thomas McGuire committed
183
// System includes
Laurent Montel's avatar
Laurent Montel committed
184
#include <AkonadiWidgets/standardactionmanager.h>
Laurent Montel's avatar
Laurent Montel committed
185
#include <QStandardPaths>
186
187
188
#include <QDBusInterface>
#include <QDBusConnection>
#include <QDBusReply>
189

Laurent Montel's avatar
Laurent Montel committed
190
#include "PimCommonAkonadi/ManageServerSideSubscriptionJob"
191
#include <job/removeduplicatemailjob.h>
Laurent Montel's avatar
Laurent Montel committed
192
#include <job/removecollectionjob.h>
193

Laurent Montel's avatar
Laurent Montel committed
194
#include <MessageViewer/DKIMWidgetInfo>
Laurent Montel's avatar
Laurent Montel committed
195
#include <MessageViewer/DKIMViewerMenu>
196
197
198
199
200
#ifdef WITH_KUSERFEEDBACK
#include <KUserFeedback/NotificationPopup>
#include <KUserFeedback/Provider>
#endif

Laurent Montel's avatar
Laurent Montel committed
201

Thomas McGuire's avatar
Thomas McGuire committed
202
using namespace KMime;
203
using namespace Akonadi;
Andras Mantia's avatar
Andras Mantia committed
204
using namespace MailCommon;
Thomas McGuire's avatar
Thomas McGuire committed
205
206
207
208
using KPIM::ProgressManager;
using KPIM::BroadcastStatus;
using KMail::SearchWindow;
using KMime::Types::AddrSpecList;
209
using MessageViewer::AttachmentStrategy;
Stephan Kulow's avatar
Stephan Kulow committed
210

Laurent Montel's avatar
Laurent Montel committed
211
Q_GLOBAL_STATIC(KMMainWidget::PtrList, theMainWidgetList)
212

Stephan Kulow's avatar
Stephan Kulow committed
213
//-----------------------------------------------------------------------------
Laurent Montel's avatar
Laurent Montel committed
214
KMMainWidget::KMMainWidget(QWidget *parent, KXMLGUIClient *aGUIClient, KActionCollection *actionCollection, const KSharedConfig::Ptr &config)
Laurent Montel's avatar
Laurent Montel committed
215
216
    : QWidget(parent)
    , mManageShowCollectionProperties(new ManageShowCollectionProperties(this, this))
Stephan Kulow's avatar
Stephan Kulow committed
217
{
218
    mLaunchExternalComponent = new KMLaunchExternalComponent(this, this);
Laurent Montel's avatar
Laurent Montel committed
219
220
221
222
223
    // must be the first line of the constructor:
    mStartupDone = false;
    mWasEverShown = false;
    mReaderWindowActive = true;
    mReaderWindowBelow = true;
224
    mFolderHtmlLoadExtPreference = false;
Laurent Montel's avatar
Laurent Montel committed
225
226
    mDestructed = false;
    mActionCollection = actionCollection;
Laurent Montel's avatar
Laurent Montel committed
227
    mTopLayout = new QVBoxLayout(this);
228
    mTopLayout->setContentsMargins(0, 0, 0, 0);
Laurent Montel's avatar
Laurent Montel committed
229
230
    mConfig = config;
    mGUIClient = aGUIClient;
Laurent Montel's avatar
Laurent Montel committed
231
    mFolderTreeWidget = nullptr;
Laurent Montel's avatar
Laurent Montel committed
232
    Akonadi::ControlGui::widgetNeedsAkonadi(this);
Laurent Montel's avatar
Laurent Montel committed
233
    mFavoritesModel = nullptr;
234
235
    mSievePasswordProvider = new KMSieveImapPasswordProvider(winId());
    mVacationManager = new KSieveUi::VacationManager(mSievePasswordProvider, this);
Laurent Montel's avatar
Laurent Montel committed
236
    connect(mVacationManager, &KSieveUi::VacationManager::updateVacationScriptStatus, this, qOverload<bool, const QString &>(&KMMainWidget::updateVacationScriptStatus));
Laurent Montel's avatar
Laurent Montel committed
237

238
239
240
241
242
243
#ifdef WITH_KUSERFEEDBACK
    mUserFeedBackNotificationPopup = new KUserFeedback::NotificationPopup(this);
    mUserFeedBackNotificationPopup->setFeedbackProvider(kmkernel->userFeedbackProvider());
#endif


Laurent Montel's avatar
Laurent Montel committed
244
245
    mToolbarActionSeparator = new QAction(this);
    mToolbarActionSeparator->setSeparator(true);
Laurent Montel's avatar
Laurent Montel committed
246

Laurent Montel's avatar
Laurent Montel committed
247
248
249
    KMailPluginInterface::self()->setActionCollection(mActionCollection);
    KMailPluginInterface::self()->initializePlugins();
    KMailPluginInterface::self()->setMainWidget(this);
Laurent Montel's avatar
Laurent Montel committed
250

Laurent Montel's avatar
Laurent Montel committed
251
    theMainWidgetList->append(this);
Laurent Montel's avatar
Laurent Montel committed
252
253
254
255
256
257
258

    readPreConfig();
    createWidgets();
    setupActions();

    readConfig();

Laurent Montel's avatar
Laurent Montel committed
259
    if (!kmkernel->isOffline()) {   //kmail is set to online mode, make sure the agents are also online
Laurent Montel's avatar
Laurent Montel committed
260
261
262
        kmkernel->setAccountStatus(true);
    }

263
    QTimer::singleShot(0, this, &KMMainWidget::slotShowStartupFolder);
Laurent Montel's avatar
Laurent Montel committed
264

265
266
    connect(kmkernel, &KMKernel::startCheckMail,
            this, &KMMainWidget::slotStartCheckMail);
Laurent Montel's avatar
Laurent Montel committed
267

268
269
    connect(kmkernel, &KMKernel::endCheckMail,
            this, &KMMainWidget::slotEndCheckMail);
Laurent Montel's avatar
Laurent Montel committed
270

271
272
    connect(kmkernel, &KMKernel::configChanged,
            this, &KMMainWidget::slotConfigChanged);
Laurent Montel's avatar
Laurent Montel committed
273

274
275
    connect(kmkernel, &KMKernel::onlineStatusChanged,
            this, &KMMainWidget::slotUpdateOnlineStatus);
Laurent Montel's avatar
Laurent Montel committed
276

Laurent Montel's avatar
Laurent Montel committed
277
278
    connect(mTagActionManager, &KMail::TagActionManager::tagActionTriggered,
            this, &KMMainWidget::slotUpdateMessageTagList);
Laurent Montel's avatar
Laurent Montel committed
279

Laurent Montel's avatar
Laurent Montel committed
280
281
    connect(mTagActionManager, &KMail::TagActionManager::tagMoreActionClicked,
            this, &KMMainWidget::slotSelectMoreMessageTagList);
Laurent Montel's avatar
Laurent Montel committed
282
283
284

    kmkernel->toggleSystemTray();

Laurent Montel's avatar
Laurent Montel committed
285
286
    {
        // make sure the pages are registered only once, since there can be multiple instances of KMMainWidget
Laurent Montel's avatar
Laurent Montel committed
287
288
        static bool pagesRegistered = false;

Laurent Montel's avatar
Laurent Montel committed
289
290
291
292
293
294
295
296
297
298
        if (!pagesRegistered) {
            Akonadi::CollectionPropertiesDialog::registerPage(new PimCommon::CollectionAclPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new MailCommon::CollectionGeneralPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new CollectionMaintenancePageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new CollectionQuotaPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new CollectionTemplatesPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new MailCommon::CollectionExpiryPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new CollectionViewPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new CollectionMailingListPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new CollectionShortcutPageFactory);
Laurent Montel's avatar
Laurent Montel committed
299
300
301
302
303

            pagesRegistered = true;
        }
    }

Laurent Montel's avatar
Laurent Montel committed
304
    KMainWindow *mainWin = qobject_cast<KMainWindow *>(window());
Laurent Montel's avatar
Laurent Montel committed
305
306
    mCurrentStatusBar = mainWin ? mainWin->statusBar() : nullptr;
    mVacationScriptIndicator = new KMail::VacationScriptIndicatorWidget(mCurrentStatusBar);
Laurent Montel's avatar
Laurent Montel committed
307
    mVacationScriptIndicator->hide();
Laurent Montel's avatar
Laurent Montel committed
308

Laurent Montel's avatar
Laurent Montel committed
309
310
311
312
    mZoomLabelIndicator = new ZoomLabelWidget(mCurrentStatusBar);
    if (mMsgView) {
        setZoomChanged(mMsgView->viewer()->webViewZoomFactor());
    }
Laurent Montel's avatar
Laurent Montel committed
313
    connect(mVacationScriptIndicator, &KMail::VacationScriptIndicatorWidget::clicked, this, &KMMainWidget::slotEditVacation);
Laurent Montel's avatar
Laurent Montel committed
314
    if (KSieveUi::Util::checkOutOfOfficeOnStartup()) {
315
        QTimer::singleShot(0, this, &KMMainWidget::slotCheckVacation);
Laurent Montel's avatar
Laurent Montel committed
316
    }
Laurent Montel's avatar
Laurent Montel committed
317

318
319
    connect(mFolderTreeWidget->folderTreeView()->model(), &QAbstractItemModel::modelReset,
            this, &KMMainWidget::restoreCollectionFolderViewConfig);
Laurent Montel's avatar
Laurent Montel committed
320
321
    restoreCollectionFolderViewConfig();

Laurent Montel's avatar
Laurent Montel committed
322
    if (kmkernel->firstStart()) {
Laurent Montel's avatar
Laurent Montel committed
323
        const QStringList listOfMailerFound = MailCommon::Util::foundMailer();
324
325
326
        if (!listOfMailerFound.isEmpty()) {
            if (KMessageBox::questionYesNoList(this, i18n("Another mailer was found on system. Do you want to import data from it?"), listOfMailerFound) == KMessageBox::Yes) {
                const QString path = QStandardPaths::findExecutable(QStringLiteral("akonadiimportwizard"));
Laurent Montel's avatar
Laurent Montel committed
327
328
329
330
                if (!QProcess::startDetached(path)) {
                    KMessageBox::error(this, i18n("Could not start the import wizard. "
                                                  "Please check your installation."),
                                       i18n("Unable to start import wizard"));
Laurent Montel's avatar
Laurent Montel committed
331
332
                }
            } else {
333
                mLaunchExternalComponent->slotAccountWizard();
Laurent Montel's avatar
Laurent Montel committed
334
335
            }
        } else {
336
            mLaunchExternalComponent->slotAccountWizard();
337
338
        }
    }
Laurent Montel's avatar
Laurent Montel committed
339
340
    // must be the last line of the constructor:
    mStartupDone = true;
341

Laurent Montel's avatar
Laurent Montel committed
342
343
    mCheckMailTimer.setInterval(3 * 1000);
    mCheckMailTimer.setSingleShot(true);
Laurent Montel's avatar
Laurent Montel committed
344
    connect(&mCheckMailTimer, &QTimer::timeout, this, &KMMainWidget::slotUpdateActionsAfterMailChecking);
345
346

    setupUnifiedMailboxChecker();
347
348
}

Laurent Montel's avatar
Laurent Montel committed
349
350
QWidget *KMMainWidget::dkimWidgetInfo() const
{
351
352
353
354
    if (mMsgView) {
        return mMsgView->viewer()->dkimWidgetInfo();
    }
    return nullptr;
Laurent Montel's avatar
Laurent Montel committed
355
}
Laurent Montel's avatar
Laurent Montel committed
356

357
void KMMainWidget::restoreCollectionFolderViewConfig()
358
{
Laurent Montel's avatar
Laurent Montel committed
359
    ETMViewStateSaver *saver = new ETMViewStateSaver;
Laurent Montel's avatar
Laurent Montel committed
360
361
362
363
    saver->setView(mFolderTreeWidget->folderTreeView());
    const KConfigGroup cfg(KMKernel::self()->config(), "CollectionFolderView");
    mFolderTreeWidget->restoreHeaderState(cfg.readEntry("HeaderState", QByteArray()));
    saver->restoreState(cfg);
Laurent Montel's avatar
Laurent Montel committed
364
    //Restore startup folder
365

Laurent Montel's avatar
Laurent Montel committed
366
    Akonadi::Collection::Id id = -1;
367
368
    if (mCurrentCollection.isValid()) {
        id = mCurrentCollection.id();
Laurent Montel's avatar
Laurent Montel committed
369
    }
370

Laurent Montel's avatar
Laurent Montel committed
371
    if (id == -1) {
Laurent Montel's avatar
Laurent Montel committed
372
373
        if (KMailSettings::self()->startSpecificFolderAtStartup()) {
            Akonadi::Collection::Id startupFolder = KMailSettings::self()->startupFolder();
Laurent Montel's avatar
Laurent Montel committed
374
            if (startupFolder > 0) {
Laurent Montel's avatar
Laurent Montel committed
375
                saver->restoreCurrentItem(QStringLiteral("c%1").arg(startupFolder));
Laurent Montel's avatar
Laurent Montel committed
376
            }
Laurent Montel's avatar
Laurent Montel committed
377
378
        }
    } else {
Laurent Montel's avatar
Laurent Montel committed
379
        saver->restoreCurrentItem(QStringLiteral("c%1").arg(id));
380
    }
Stephan Kulow's avatar
Stephan Kulow committed
381
382
383
384
385
}

//-----------------------------------------------------------------------------
//The kernel may have already been deleted when this method is called,
//perform all cleanup that requires the kernel in destruct()
386
KMMainWidget::~KMMainWidget()
Stephan Kulow's avatar
Stephan Kulow committed
387
{
Laurent Montel's avatar
Laurent Montel committed
388
389
    theMainWidgetList->removeAll(this);
    qDeleteAll(mFilterCommands);
Laurent Montel's avatar
Laurent Montel committed
390
    destruct();
Stephan Kulow's avatar
Stephan Kulow committed
391
392
393
394
}

//-----------------------------------------------------------------------------
//This method performs all cleanup that requires the kernel to exist.
395
void KMMainWidget::destruct()
Stephan Kulow's avatar
Stephan Kulow committed
396
{
Laurent Montel's avatar
Laurent Montel committed
397
    if (mDestructed) {
Laurent Montel's avatar
Laurent Montel committed
398
        return;
Laurent Montel's avatar
Laurent Montel committed
399
400
    }
    if (mSearchWin) {
Laurent Montel's avatar
Laurent Montel committed
401
        mSearchWin->close();
Laurent Montel's avatar
Laurent Montel committed
402
    }
403
    disconnect(mFolderTreeWidget->folderTreeView()->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KMMainWidget::updateFolderMenu);
Laurent Montel's avatar
Laurent Montel committed
404
405
406
    writeConfig(false); /* don't force kmkernel sync when close BUG: 289287 */
    writeFolderConfig();
    deleteWidgets();
407
    clearCurrentFolder();
Laurent Montel's avatar
Laurent Montel committed
408
409
    delete mMoveOrCopyToDialog;
    delete mSelectFromAllFoldersDialog;
410
    delete mSievePasswordProvider;
Laurent Montel's avatar
Laurent Montel committed
411

Laurent Montel's avatar
Laurent Montel committed
412
413
414
415
416
    disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), this, nullptr);
    disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)), this, nullptr);
    disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), this, nullptr);
    disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)), this, nullptr);
    disconnect(kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), this, nullptr);
Laurent Montel's avatar
Laurent Montel committed
417

Laurent Montel's avatar
Laurent Montel committed
418
    mDestructed = true;
Stephan Kulow's avatar
Stephan Kulow committed
419
420
}

421
422
void KMMainWidget::clearCurrentFolder()
{
Laurent Montel's avatar
Laurent Montel committed
423
    mCurrentFolderSettings.clear();
424
425
426
    mCurrentCollection = Akonadi::Collection();
}

427
428
void KMMainWidget::slotStartCheckMail()
{
Laurent Montel's avatar
Laurent Montel committed
429
    if (mCheckMailTimer.isActive()) {
Laurent Montel's avatar
Laurent Montel committed
430
        mCheckMailTimer.stop();
Laurent Montel's avatar
Laurent Montel committed
431
    }
432
433
434
435
}

void KMMainWidget::slotEndCheckMail()
{
Laurent Montel's avatar
Laurent Montel committed
436
    if (!mCheckMailTimer.isActive()) {
Laurent Montel's avatar
Laurent Montel committed
437
        mCheckMailTimer.start();
Laurent Montel's avatar
Laurent Montel committed
438
    }
439
440
}

Laurent Montel's avatar
Laurent Montel committed
441
void KMMainWidget::slotUpdateActionsAfterMailChecking()
442
{
Laurent Montel's avatar
Laurent Montel committed
443
444
445
446
    const bool sendOnAll
        = KMailSettings::self()->sendOnCheck() == KMailSettings::EnumSendOnCheck::SendOnAllChecks;
    const bool sendOnManual
        = KMailSettings::self()->sendOnCheck() == KMailSettings::EnumSendOnCheck::SendOnManualChecks;
Laurent Montel's avatar
Laurent Montel committed
447
    if (!kmkernel->isOffline() && (sendOnAll || sendOnManual)) {
Laurent Montel's avatar
Laurent Montel committed
448
449
450
451
452
        slotSendQueued();
    }
    // update folder menus in case some mail got filtered to trash/current folder
    // and we can enable "empty trash/move all to trash" action etc.
    updateFolderMenu();
453
454
}

455
456
457
void KMMainWidget::setCurrentCollection(const Akonadi::Collection &col)
{
    mCurrentCollection = col;
Laurent Montel's avatar
Laurent Montel committed
458
459
    if (mCurrentFolderSettings) {
        mCurrentFolderSettings->setCollection(col);
460
461
462
    }
}

Laurent Montel's avatar
Laurent Montel committed
463
void KMMainWidget::slotCollectionFetched(int collectionId)
464
{
Laurent Montel's avatar
Laurent Montel committed
465
466
467
    // Called when a collection is fetched for the first time by the ETM.
    // This is the right time to update the caption (which still says "Loading...")
    // and to update the actions that depend on the number of mails in the folder.
468
    if (collectionId == mCurrentCollection.id()) {
469
        setCurrentCollection(CommonKernel->collectionFromId(mCurrentCollection.id()));
Laurent Montel's avatar
Laurent Montel committed
470
471
472
473
        updateMessageActions();
        updateFolderMenu();
    }
    // We call this for any collection, it could be one of our parents...
474
    if (mCurrentCollection.isValid()) {
475
        Q_EMIT captionChangeRequest(fullCollectionPath());
Laurent Montel's avatar
Laurent Montel committed
476
    }
477
478
}

479
480
481
482
483
484
485
QString KMMainWidget::fullCollectionPath() const
{
    if (mCurrentCollection.isValid()) {
        return MailCommon::Util::fullCollectionPath(mCurrentCollection);
    }
    return {};
}
486

487
// Connected to the currentChanged signals from the folderTreeView and favorites view.
Laurent Montel's avatar
Laurent Montel committed
488
void KMMainWidget::slotFolderChanged(const Akonadi::Collection &collection)
489
{
Laurent Montel's avatar
Laurent Montel committed
490
    if (mCurrentCollection == collection) {
491
        return;
Laurent Montel's avatar
Laurent Montel committed
492
    }
Laurent Montel's avatar
Laurent Montel committed
493
494
495
496
497
    folderSelected(collection);
    if (collection.cachePolicy().syncOnDemand()) {
        AgentManager::self()->synchronizeCollection(collection, false);
    }
    mMsgActions->setCurrentMessage(Akonadi::Item());
Laurent Montel's avatar
Laurent Montel committed
498
    Q_EMIT captionChangeRequest(MailCommon::Util::fullCollectionPath(collection));
Laurent Montel's avatar
Laurent Montel committed
499
500
}

501
// Called by slotFolderChanged (no particular reason for this method to be split out)
Laurent Montel's avatar
Laurent Montel committed
502
void KMMainWidget::folderSelected(const Akonadi::Collection &col)
Laurent Montel's avatar
Laurent Montel committed
503
{
Laurent Montel's avatar
Laurent Montel committed
504
    if (mGoToFirstUnreadMessageInSelectedFolder) {
Laurent Montel's avatar
Laurent Montel committed
505
        // the default action has been overridden from outside
506
        mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered;
Laurent Montel's avatar
Laurent Montel committed
507
508
    } else {
        // use the default action
Laurent Montel's avatar
Laurent Montel committed
509
510
        switch (KMailSettings::self()->actionEnterFolder()) {
        case KMailSettings::EnumActionEnterFolder::SelectFirstUnread:
Laurent Montel's avatar
Laurent Montel committed
511
512
            mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered;
            break;
Laurent Montel's avatar
Laurent Montel committed
513
        case KMailSettings::EnumActionEnterFolder::SelectLastSelected:
Laurent Montel's avatar
Laurent Montel committed
514
515
            mPreSelectionMode = MessageList::Core::PreSelectLastSelected;
            break;
Laurent Montel's avatar
Laurent Montel committed
516
        case KMailSettings::EnumActionEnterFolder::SelectNewest:
Laurent Montel's avatar
Laurent Montel committed
517
518
            mPreSelectionMode = MessageList::Core::PreSelectNewestCentered;
            break;
Laurent Montel's avatar
Laurent Montel committed
519
        case KMailSettings::EnumActionEnterFolder::SelectOldest:
Laurent Montel's avatar
Laurent Montel committed
520
521
522
523
524
525
526
527
528
            mPreSelectionMode = MessageList::Core::PreSelectOldestCentered;
            break;
        default:
            mPreSelectionMode = MessageList::Core::PreSelectNone;
            break;
        }
    }

    mGoToFirstUnreadMessageInSelectedFolder = false;
529
#ifndef QT_NO_CURSOR
530
    KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
531
#endif
Laurent Montel's avatar
Laurent Montel committed
532

Laurent Montel's avatar
Laurent Montel committed
533
    if (mMsgView) {
Laurent Montel's avatar
Laurent Montel committed
534
        mMsgView->clear(true);
Laurent Montel's avatar
Laurent Montel committed
535
    }
536
    const bool newFolder = mCurrentCollection != col;
David Faure's avatar
David Faure committed
537

Laurent Montel's avatar
Laurent Montel committed
538
539
    // Delete any pending timer, if needed it will be recreated below
    delete mShowBusySplashTimer;
Laurent Montel's avatar
Laurent Montel committed
540
    mShowBusySplashTimer = nullptr;
Laurent Montel's avatar
Laurent Montel committed
541
    if (newFolder) {
Laurent Montel's avatar
Laurent Montel committed
542
543
544
        // We're changing folder: write configuration for the old one
        writeFolderConfig();
    }
Laurent Montel's avatar
Laurent Montel committed
545

Laurent Montel's avatar
Laurent Montel committed
546
    mCurrentFolderSettings = FolderSettings::forCollection(col);
547
    mCurrentCollection = col;
Laurent Montel's avatar
Laurent Montel committed
548

Laurent Montel's avatar
Laurent Montel committed
549
    readFolderConfig();
Laurent Montel's avatar
Laurent Montel committed
550
    if (mMsgView) {
551
        assignLoadExternalReference();
Laurent Montel's avatar
Laurent Montel committed
552
    }
Laurent Montel's avatar
Laurent Montel committed
553

Laurent Montel's avatar
Laurent Montel committed
554
    if (!mCurrentFolderSettings->isValid() && (mMessagePane->count() < 2)) {
Laurent Montel's avatar
Laurent Montel committed
555
        slotIntro();
556
557
558
559
    } else {
        if (mMessagePane->isHidden()) {
            mMessagePane->show();
        }
Laurent Montel's avatar
Laurent Montel committed
560
    }
Laurent Montel's avatar
Laurent Montel committed
561

Laurent Montel's avatar
Laurent Montel committed
562
563
564
    // The message pane uses the selection model of the folder view to load the correct aggregation model and theme
    //  settings. At this point the selection model hasn't been updated yet to the user's new choice, so it would load
    //  the old folder settings instead.
565
    QTimer::singleShot(0, this, &KMMainWidget::slotShowSelectedFolderInPane);
566
567
}

Laurent Montel's avatar
Laurent Montel committed
568
void KMMainWidget::slotShowSelectedFolderInPane()
569
{
570
    if (mCurrentCollection.isValid()) {
571
572
        QModelIndex idx = Akonadi::EntityTreeModel::modelIndexForCollection(KMKernel::self()->entityTreeModel(), mCurrentCollection);
        mMessagePane->setCurrentFolder(mCurrentCollection, idx, false, mPreSelectionMode);
Laurent Montel's avatar
Laurent Montel committed
573
    }
Laurent Montel's avatar
Laurent Montel committed
574
575
    updateMessageActions();
    updateFolderMenu();
576
577
}

Stephan Kulow's avatar
Stephan Kulow committed
578
//-----------------------------------------------------------------------------
579
void KMMainWidget::readPreConfig()
Stephan Kulow's avatar
Stephan Kulow committed
580
{
Laurent Montel's avatar
Laurent Montel committed
581
582
583
    mLongFolderList = KMailSettings::self()->folderList() == KMailSettings::EnumFolderList::longlist;
    mReaderWindowActive = KMailSettings::self()->readerWindowMode() != KMailSettings::EnumReaderWindowMode::hide;
    mReaderWindowBelow = KMailSettings::self()->readerWindowMode() == KMailSettings::EnumReaderWindowMode::below;
Dirk Mueller's avatar
Dirk Mueller committed
584

Laurent Montel's avatar
Laurent Montel committed
585
586
    mHtmlGlobalSetting = MessageViewer::MessageViewerSettings::self()->htmlMail();
    mHtmlLoadExtGlobalSetting = MessageViewer::MessageViewerSettings::self()->htmlLoadExternal();
Laurent Montel's avatar
Laurent Montel committed
587

Laurent Montel's avatar
Laurent Montel committed
588
    mEnableFavoriteFolderView = (KMKernel::self()->mailCommonSettings()->favoriteCollectionViewMode() != MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode);
589
590
    mEnableFolderQuickSearch = KMailSettings::self()->enableFolderQuickSearch();

591
    readFolderConfig();
Laurent Montel's avatar
Laurent Montel committed
592
    updateHtmlMenuEntry();
593
594
    if (mMsgView) {
        mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
Laurent Montel's avatar
Laurent Montel committed
595
        mMsgView->update(true);
596
    }
Stephan Kulow's avatar
Stephan Kulow committed
597
598
599
}

//-----------------------------------------------------------------------------
600
void KMMainWidget::readFolderConfig()
Stephan Kulow's avatar
Stephan Kulow committed
601
{
Laurent Montel's avatar
Laurent Montel committed
602
    if (!mCurrentCollection.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
603
        return;
Laurent Montel's avatar
Laurent Montel committed
604
    }
Laurent Montel's avatar
Laurent Montel committed
605
    KSharedConfig::Ptr config = KMKernel::self()->config();
Laurent Montel's avatar
Laurent Montel committed
606
    KConfigGroup group(config, MailCommon::FolderSettings::configGroupName(mCurrentCollection));
Laurent Montel's avatar
Laurent Montel committed
607
608
    if (group.hasKey("htmlMailOverride")) {
        const bool useHtml = group.readEntry("htmlMailOverride", false);
609
610
611
612
        mFolderDisplayFormatPreference = useHtml ? MessageViewer::Viewer::Html : MessageViewer::Viewer::Text;
        group.deleteEntry("htmlMailOverride");
        group.sync();
    } else {
Laurent Montel's avatar
Laurent Montel committed
613
        mFolderDisplayFormatPreference = static_cast<MessageViewer::Viewer::DisplayFormatMessage>(group.readEntry("displayFormatOverride", static_cast<int>(MessageViewer::Viewer::UseGlobalSetting)));
614
    }
Laurent Montel's avatar
Laurent Montel committed
615
616
    mFolderHtmlLoadExtPreference
        = group.readEntry("htmlLoadExternalOverride", false);
Stephan Kulow's avatar
Stephan Kulow committed
617
618
619
}

//-----------------------------------------------------------------------------
620
void KMMainWidget::writeFolderConfig()
Stephan Kulow's avatar
Stephan Kulow committed
621
{
622
    if (mCurrentCollection.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
623
        KSharedConfig::Ptr config = KMKernel::self()->config();
Laurent Montel's avatar
Laurent Montel committed
624
        KConfigGroup group(config, MailCommon::FolderSettings::configGroupName(mCurrentCollection));
625
626
627
628
629
        if (mFolderHtmlLoadExtPreference) {
            group.writeEntry("htmlLoadExternalOverride", mFolderHtmlLoadExtPreference);
        } else {
            group.deleteEntry("htmlLoadExternalOverride");
        }
Laurent Montel's avatar
Laurent Montel committed
630
        if (mFolderDisplayFormatPreference == MessageViewer::Viewer::UseGlobalSetting) {
631
            group.deleteEntry("displayFormatOverride");
Laurent Montel's avatar
Laurent Montel committed
632
633
634
        } else {
            group.writeEntry("displayFormatOverride", static_cast<int>(mFolderDisplayFormatPreference));
        }
Laurent Montel's avatar
Laurent Montel committed
635
    }
Stephan Kulow's avatar
Stephan Kulow committed
636
637
}

638
639
640
//-----------------------------------------------------------------------------
void KMMainWidget::layoutSplitters()
{
Laurent Montel's avatar
Laurent Montel committed
641
    // This function can only be called when the old splitters are already deleted
Laurent Montel's avatar
Laurent Montel committed
642
643
    Q_ASSERT(!mSplitter1);
    Q_ASSERT(!mSplitter2);
644

Laurent Montel's avatar
Laurent Montel committed
645
646
    // For some reason, this is necessary here so that the copy action still
    // works after changing the folder layout.
Laurent Montel's avatar
Laurent Montel committed
647
    if (mMsgView) {
Laurent Montel's avatar
Laurent Montel committed
648
649
        disconnect(mMsgView->copyAction(), &QAction::triggered,
                   mMsgView, &KMReaderWin::slotCopySelectedText);
Laurent Montel's avatar
Laurent Montel committed
650
    }
Laurent Montel's avatar
Laurent Montel committed
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665

    // If long folder list is enabled, the splitters are:
    // Splitter 1: FolderView vs (HeaderAndSearch vs MessageViewer)
    // Splitter 2: HeaderAndSearch vs MessageViewer
    //
    // If long folder list is disabled, the splitters are:
    // Splitter 1: (FolderView vs HeaderAndSearch) vs MessageViewer
    // Splitter 2: FolderView vs HeaderAndSearch

    // The folder view is both the folder tree and the favorite folder view, if
    // enabled

    const bool readerWindowAtSide = !mReaderWindowBelow && mReaderWindowActive;
    const bool readerWindowBelow = mReaderWindowBelow && mReaderWindowActive;

Laurent Montel's avatar
Laurent Montel committed
666
667
    mSplitter1 = new QSplitter(this);
    mSplitter2 = new QSplitter(mSplitter1);
Laurent Montel's avatar
Laurent Montel committed
668

669
    QWidget *folderTreeWidget = mFolderTreeWidget;
Laurent Montel's avatar
Laurent Montel committed
670
671
    if (mFavoriteCollectionsView) {
        mFolderViewSplitter = new QSplitter(Qt::Vertical);
Laurent Montel's avatar
Laurent Montel committed
672
        mFolderViewSplitter->setChildrenCollapsible(false);
Laurent Montel's avatar
Laurent Montel committed
673
        mFolderViewSplitter->addWidget(mFavoriteCollectionsView);
674
        mFolderViewSplitter->addWidget(mFolderTreeWidget);
Laurent Montel's avatar
Laurent Montel committed
675
        folderTreeWidget = mFolderViewSplitter;
Till Adam's avatar
Till Adam committed
676
    }
677

Laurent Montel's avatar
Laurent Montel committed
678
    if (mLongFolderList) {
Laurent Montel's avatar
Laurent Montel committed
679
        // add folder tree
Laurent Montel's avatar
Laurent Montel committed
680
681
        mSplitter1->setOrientation(Qt::Horizontal);
        mSplitter1->addWidget(folderTreeWidget);
Laurent Montel's avatar
Laurent Montel committed
682
683

        // and the rest to the right
Laurent Montel's avatar
Laurent Montel committed
684
        mSplitter1->addWidget(mSplitter2);
Laurent Montel's avatar
Laurent Montel committed
685
686

        // add the message list to the right or below
Laurent Montel's avatar
Laurent Montel committed
687
688
        if (readerWindowAtSide) {
            mSplitter2->setOrientation(Qt::Horizontal);
Laurent Montel's avatar
Laurent Montel committed
689
        } else {
Laurent Montel's avatar
Laurent Montel committed
690
            mSplitter2->setOrientation(Qt::Vertical);
Laurent Montel's avatar
Laurent Montel committed
691
        }
Laurent Montel's avatar
Laurent Montel committed
692
        mSplitter2->addWidget(mMessagePane);
Laurent Montel's avatar
Laurent Montel committed
693
694

        // add the preview window, if there is one
Laurent Montel's avatar
Laurent Montel committed
695
696
        if (mMsgView) {
            mSplitter2->addWidget(mMsgView);
Laurent Montel's avatar
Laurent Montel committed
697
698
        }
    } else { // short folder list
Laurent Montel's avatar
Laurent Montel committed
699
700
701
        if (mReaderWindowBelow) {
            mSplitter1->setOrientation(Qt::Vertical);
            mSplitter2->setOrientation(Qt::Horizontal);
Laurent Montel's avatar
Laurent Montel committed
702
        } else { // at side or none
Laurent Montel's avatar
Laurent Montel committed
703
704
            mSplitter1->setOrientation(Qt::Horizontal);
            mSplitter2->setOrientation(Qt::Vertical);
Laurent Montel's avatar
Laurent Montel committed
705
706
        }

Laurent Montel's avatar
Laurent Montel committed
707
        mSplitter1->addWidget(mSplitter2);
Laurent Montel's avatar
Laurent Montel committed
708
709

        // add folder tree
Laurent Montel's avatar
Laurent Montel committed
710
        mSplitter2->addWidget(folderTreeWidget);
Laurent Montel's avatar
Laurent Montel committed
711
        // add message list to splitter 2
Laurent Montel's avatar
Laurent Montel committed
712
        mSplitter2->addWidget(mMessagePane);
Laurent Montel's avatar
Laurent Montel committed
713
714

        // add the preview window, if there is one
Laurent Montel's avatar
Laurent Montel committed
715
716
717
        if (mMsgView) {
            mSplitter1->addWidget(mMsgView);
        }
Till Adam's avatar
Till Adam committed
718
    }
719

Laurent Montel's avatar
Laurent Montel committed
720
721
722
    //
    // Set splitter properties
    //
Laurent Montel's avatar
Laurent Montel committed
723
    mSplitter1->setObjectName(QStringLiteral("splitter1"));
Laurent Montel's avatar
Laurent Montel committed
724
    mSplitter1->setChildrenCollapsible(false);
Laurent Montel's avatar
Laurent Montel committed
725
    mSplitter2->setObjectName(QStringLiteral("splitter2"));
Laurent Montel's avatar
Laurent Montel committed
726
    mSplitter2->setChildrenCollapsible(false);
Laurent Montel's avatar
Laurent Montel committed
727
728
729
730

    //
    // Set the stretch factors
    //
Laurent Montel's avatar
Laurent Montel committed
731
732
733
734
    mSplitter1->setStretchFactor(0, 0);
    mSplitter2->setStretchFactor(0, 0);
    mSplitter1->setStretchFactor(1, 1);
    mSplitter2->setStretchFactor(1, 1);
Laurent Montel's avatar
Laurent Montel committed
735

Laurent Montel's avatar
Laurent Montel committed
736
737
738
    if (mFavoriteCollectionsView) {
        mFolderViewSplitter->setStretchFactor(0, 0);
        mFolderViewSplitter->setStretchFactor(1, 1);
Laurent Montel's avatar
Laurent Montel committed
739
    }
740

Laurent Montel's avatar
Laurent Montel committed
741
742
743
    // Because the reader windows's width increases a tiny bit after each
    // restart in short folder list mode with message window at side, disable
    // the stretching as a workaround here
Laurent Montel's avatar
Laurent Montel committed
744
745
746
    if (readerWindowAtSide && !mLongFolderList) {
        mSplitter1->setStretchFactor(0, 1);
        mSplitter1->setStretchFactor(1, 0);
Laurent Montel's avatar
Laurent Montel committed
747
    }
748

Laurent Montel's avatar
Laurent Montel committed
749
750
751
752
753
754
    //
    // Set the sizes of the splitters to the values stored in the config
    //
    QList<int> splitter1Sizes;
    QList<int> splitter2Sizes;

Laurent Montel's avatar
Laurent Montel committed
755
756
757
758
759
760
    const int folderViewWidth = KMailSettings::self()->folderViewWidth();
    int ftHeight = KMailSettings::self()->folderTreeHeight();
    int headerHeight = KMailSettings::self()->searchAndHeaderHeight();
    const int messageViewerWidth = KMailSettings::self()->readerWindowWidth();
    int headerWidth = KMailSettings::self()->searchAndHeaderWidth();
    int messageViewerHeight = KMailSettings::self()->readerWindowHeight();
Laurent Montel's avatar
Laurent Montel committed
761

Laurent Montel's avatar
Laurent Montel committed
762
    int ffvHeight = mFolderViewSplitter ? KMKernel::self()->mailCommonSettings()->favoriteCollectionViewHeight() : 0;
Laurent Montel's avatar
Laurent Montel committed
763
764

    // If the message viewer was hidden before, make sure it is not zero height
Laurent Montel's avatar
Laurent Montel committed
765
    if (messageViewerHeight < 10 && readerWindowBelow) {
Laurent Montel's avatar
Laurent Montel committed
766
767
        headerHeight /= 2;
        messageViewerHeight = headerHeight;
768
    }
Laurent Montel's avatar
Laurent Montel committed
769

Laurent Montel's avatar
Laurent Montel committed
770
771
    if (mLongFolderList) {
        if (!readerWindowAtSide) {
Laurent Montel's avatar
Laurent Montel committed
772
773
774
            splitter1Sizes << folderViewWidth << headerWidth;
            splitter2Sizes << headerHeight << messageViewerHeight;
        } else {
Laurent Montel's avatar
Laurent Montel committed
775
            splitter1Sizes << folderViewWidth << (headerWidth + messageViewerWidth);
Laurent Montel's avatar
Laurent Montel committed
776
777
            splitter2Sizes << headerWidth << messageViewerWidth;
        }
778
    } else {
Laurent Montel's avatar
Laurent Montel committed
779
        if (!readerWindowAtSide) {
Laurent Montel's avatar
Laurent Montel committed
780
781
782
783
784
785
            splitter1Sizes << headerHeight << messageViewerHeight;
            splitter2Sizes << folderViewWidth << headerWidth;
        } else {
            splitter1Sizes << headerWidth << messageViewerWidth;
            splitter2Sizes << ftHeight + ffvHeight << messageViewerHeight;
        }
786
787
    }

Laurent Montel's avatar
Laurent Montel committed
788
789
    mSplitter1->setSizes(splitter1Sizes);
    mSplitter2->setSizes(splitter2Sizes);
790

Laurent Montel's avatar
Laurent Montel committed
791
    if (mFolderViewSplitter) {
Laurent Montel's avatar
Laurent Montel committed
792
793
        QList<int> splitterSizes;
        splitterSizes << ffvHeight << ftHeight;
Laurent Montel's avatar
Laurent Montel committed
794
        mFolderViewSplitter->setSizes(splitterSizes);
Laurent Montel's avatar
Laurent Montel committed
795
    }
796

Laurent Montel's avatar
Laurent Montel committed
797
798
799
    //
    // Now add the splitters to the main layout
    //
Laurent Montel's avatar
Laurent Montel committed
800
    mTopLayout->addWidget(mSplitter1);
801

Laurent Montel's avatar
Laurent Montel committed
802
803
804
805
806
    // Make sure the focus is on the view, and not on the quick search line edit, because otherwise
    // shortcuts like + or j go to the wrong place.
    // This would normally be done in the message list itself, but apparently something resets the focus
    // again, probably all the reparenting we do here.
    mMessagePane->focusView();
Laurent Montel's avatar
Laurent Montel committed
807

Laurent Montel's avatar
Laurent Montel committed
808
    // By default hide th unread and size columns on first run.
Laurent Montel's avatar
Laurent Montel committed
809
810
811
    if (kmkernel->firstStart()) {
        mFolderTreeWidget->folderTreeView()->hideColumn(1);
        mFolderTreeWidget->folderTreeView()->hideColumn(3);
Laurent Montel's avatar
Laurent Montel committed
812
        mFolderTreeWidget->folderTreeView()->header()->resizeSection(0, static_cast<int>(folderViewWidth * 0.8));
Laurent Montel's avatar
Laurent Montel committed
813
    }
814

Laurent Montel's avatar
Laurent Montel committed
815
    // Make the copy action work, see disconnect comment above
Laurent Montel's avatar
Laurent Montel committed
816
    if (mMsgView) {
Laurent Montel's avatar
Laurent Montel committed
817
818
        connect(mMsgView->copyAction(), &QAction::triggered,
                mMsgView, &KMReaderWin::slotCopySelectedText);
Laurent Montel's avatar
Laurent Montel committed
819
    }
820
}
Stephan Kulow's avatar
Stephan Kulow committed
821

822
823
824
//-----------------------------------------------------------------------------
void KMMainWidget::refreshFavoriteFoldersViewProperties()
{
Laurent Montel's avatar
Laurent Montel committed
825
    if (mFavoriteCollectionsView) {
Laurent Montel's avatar
Laurent Montel committed
826
        if (KMKernel::self()->mailCommonSettings()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode) {
Laurent Montel's avatar
Laurent Montel committed
827
            mFavoriteCollectionsView->changeViewMode(QListView::IconMode);
Laurent Montel's avatar
Laurent Montel committed
828
        } else if (KMKernel::self()->mailCommonSettings()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode) {
Laurent Montel's avatar
Laurent Montel committed
829
830
831
832
833
834
            mFavoriteCollectionsView->changeViewMode(QListView::ListMode);
        } else {
            Q_ASSERT(false);    // we should never get here in hidden mode
        }
        mFavoriteCollectionsView->setDropActionMenuEnabled(kmkernel->showPopupAfterDnD());
        mFavoriteCollectionsView->setWordWrap(true);
Laurent Montel's avatar
Laurent Montel committed
835
836
        mFavoriteCollectionsView->updateMode();
    }
837
838
}

Stephan Kulow's avatar
Stephan Kulow committed
839
//-----------------------------------------------------------------------------
840
void KMMainWidget::readConfig()
Stephan Kulow's avatar
Stephan Kulow committed
841
{
Laurent Montel's avatar
Laurent Montel committed
842
843
844
845
    const bool oldLongFolderList = mLongFolderList;
    const bool oldReaderWindowActive = mReaderWindowActive;
    const bool oldReaderWindowBelow = mReaderWindowBelow;
    const bool oldFavoriteFolderView = mEnableFavoriteFolderView;
846
    const bool oldFolderQuickSearch = mEnableFolderQuickSearch;
847

Laurent Montel's avatar
Laurent Montel committed
848
849
    // on startup, the layout is always new and we need to relayout the widgets
    bool layoutChanged = !mStartupDone;
Stephan Kulow's avatar
Stephan Kulow committed
850

Laurent Montel's avatar
Laurent Montel committed
851
    if (mStartupDone) {