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-2019 Montel Laurent <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 "PimCommon/NetworkUtil"
Laurent Montel's avatar
Laurent Montel committed
53
#include "kpimtextedit/texttospeech.h"
54
#include "job/markallmessagesasreadinfolderandsubfolderjob.h"
55
#include "job/removeduplicatemessageinfolderandsubfolderjob.h"
56
#include "sieveimapinterface/kmsieveimappasswordprovider.h"
Laurent Montel's avatar
Laurent Montel committed
57
#include <KSieveUi/SieveDebugDialog>
58

59
#include <AkonadiWidgets/CollectionMaintenancePage>
Laurent Montel's avatar
Laurent Montel committed
60
61
62
63
64
#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
65
#include "tag/tagselectdialog.h"
Laurent Montel's avatar
Laurent Montel committed
66
#include "job/createnewcontactjob.h"
67
68
#include "folderarchive/folderarchiveutil.h"
#include "folderarchive/folderarchivemanager.h"
69

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

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

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

90
#include <MessageViewer/AttachmentStrategy>
91

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

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

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

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

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

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

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

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

150
151
#include <PimCommon/LogActivitiesManager>

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

162
163
164
165
166
167
168
169
170
#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
171
172
#include <QStatusBar>
#include <QAction>
Laurent Montel's avatar
Laurent Montel committed
173
#include <KRecentFilesAction>
174

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

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

Laurent Montel's avatar
Laurent Montel committed
195
196
197
198
#ifdef USE_DKIM_CHECKER
#include <MessageViewer/DKIMWidgetInfo>
#endif

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

Laurent Montel's avatar
Laurent Montel committed
208
Q_GLOBAL_STATIC(KMMainWidget::PtrList, theMainWidgetList)
209

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

Laurent Montel's avatar
Laurent Montel committed
235
236
    mToolbarActionSeparator = new QAction(this);
    mToolbarActionSeparator->setSeparator(true);
Laurent Montel's avatar
Laurent Montel committed
237

Laurent Montel's avatar
Laurent Montel committed
238
239
240
    KMailPluginInterface::self()->setActionCollection(mActionCollection);
    KMailPluginInterface::self()->initializePlugins();
    KMailPluginInterface::self()->setMainWidget(this);
Laurent Montel's avatar
Laurent Montel committed
241

Laurent Montel's avatar
Laurent Montel committed
242
    theMainWidgetList->append(this);
Laurent Montel's avatar
Laurent Montel committed
243
244
245
246
247
248
249

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

    readConfig();

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

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

256
257
    connect(kmkernel, &KMKernel::startCheckMail,
            this, &KMMainWidget::slotStartCheckMail);
Laurent Montel's avatar
Laurent Montel committed
258

259
260
    connect(kmkernel, &KMKernel::endCheckMail,
            this, &KMMainWidget::slotEndCheckMail);
Laurent Montel's avatar
Laurent Montel committed
261

262
263
    connect(kmkernel, &KMKernel::configChanged,
            this, &KMMainWidget::slotConfigChanged);
Laurent Montel's avatar
Laurent Montel committed
264

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

Laurent Montel's avatar
Laurent Montel committed
268
269
    connect(mTagActionManager, &KMail::TagActionManager::tagActionTriggered,
            this, &KMMainWidget::slotUpdateMessageTagList);
Laurent Montel's avatar
Laurent Montel committed
270

Laurent Montel's avatar
Laurent Montel committed
271
272
    connect(mTagActionManager, &KMail::TagActionManager::tagMoreActionClicked,
            this, &KMMainWidget::slotSelectMoreMessageTagList);
Laurent Montel's avatar
Laurent Montel committed
273
274
275

    kmkernel->toggleSystemTray();

Laurent Montel's avatar
Laurent Montel committed
276
277
    {
        // make sure the pages are registered only once, since there can be multiple instances of KMMainWidget
Laurent Montel's avatar
Laurent Montel committed
278
279
        static bool pagesRegistered = false;

Laurent Montel's avatar
Laurent Montel committed
280
281
282
283
284
285
286
287
288
289
        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
290
291
292
293
294

            pagesRegistered = true;
        }
    }

Laurent Montel's avatar
Laurent Montel committed
295
    KMainWindow *mainWin = qobject_cast<KMainWindow *>(window());
Laurent Montel's avatar
Laurent Montel committed
296
297
    mCurrentStatusBar = mainWin ? mainWin->statusBar() : nullptr;
    mVacationScriptIndicator = new KMail::VacationScriptIndicatorWidget(mCurrentStatusBar);
Laurent Montel's avatar
Laurent Montel committed
298
    mVacationScriptIndicator->hide();
Laurent Montel's avatar
Laurent Montel committed
299

Laurent Montel's avatar
Laurent Montel committed
300
301
302
303
    mZoomLabelIndicator = new ZoomLabelWidget(mCurrentStatusBar);
    if (mMsgView) {
        setZoomChanged(mMsgView->viewer()->webViewZoomFactor());
    }
Laurent Montel's avatar
Laurent Montel committed
304
    connect(mVacationScriptIndicator, &KMail::VacationScriptIndicatorWidget::clicked, this, &KMMainWidget::slotEditVacation);
Laurent Montel's avatar
Laurent Montel committed
305
    if (KSieveUi::Util::checkOutOfOfficeOnStartup()) {
306
        QTimer::singleShot(0, this, &KMMainWidget::slotCheckVacation);
Laurent Montel's avatar
Laurent Montel committed
307
    }
Laurent Montel's avatar
Laurent Montel committed
308

309
310
    connect(mFolderTreeWidget->folderTreeView()->model(), &QAbstractItemModel::modelReset,
            this, &KMMainWidget::restoreCollectionFolderViewConfig);
Laurent Montel's avatar
Laurent Montel committed
311
312
    restoreCollectionFolderViewConfig();

Laurent Montel's avatar
Laurent Montel committed
313
    if (kmkernel->firstStart()) {
Laurent Montel's avatar
Laurent Montel committed
314
        const QStringList listOfMailerFound = MailCommon::Util::foundMailer();
315
316
317
        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
318
319
320
321
                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
322
323
                }
            } else {
324
                mLaunchExternalComponent->slotAccountWizard();
Laurent Montel's avatar
Laurent Montel committed
325
326
            }
        } else {
327
            mLaunchExternalComponent->slotAccountWizard();
328
329
        }
    }
Laurent Montel's avatar
Laurent Montel committed
330
331
    // must be the last line of the constructor:
    mStartupDone = true;
332

Laurent Montel's avatar
Laurent Montel committed
333
334
    mCheckMailTimer.setInterval(3 * 1000);
    mCheckMailTimer.setSingleShot(true);
Laurent Montel's avatar
Laurent Montel committed
335
    connect(&mCheckMailTimer, &QTimer::timeout, this, &KMMainWidget::slotUpdateActionsAfterMailChecking);
336
337

    setupUnifiedMailboxChecker();
338
339
}

Laurent Montel's avatar
Laurent Montel committed
340
341
342
#ifdef USE_DKIM_CHECKER
QWidget *KMMainWidget::dkimWidgetInfo() const
{
343
344
345
346
    if (mMsgView) {
        return mMsgView->viewer()->dkimWidgetInfo();
    }
    return nullptr;
Laurent Montel's avatar
Laurent Montel committed
347
348
349
}
#endif

350
void KMMainWidget::restoreCollectionFolderViewConfig()
351
{
Laurent Montel's avatar
Laurent Montel committed
352
    ETMViewStateSaver *saver = new ETMViewStateSaver;
Laurent Montel's avatar
Laurent Montel committed
353
354
355
356
    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
357
    //Restore startup folder
358

Laurent Montel's avatar
Laurent Montel committed
359
    Akonadi::Collection::Id id = -1;
360
361
    if (mCurrentCollection.isValid()) {
        id = mCurrentCollection.id();
Laurent Montel's avatar
Laurent Montel committed
362
    }
363

Laurent Montel's avatar
Laurent Montel committed
364
    if (id == -1) {
Laurent Montel's avatar
Laurent Montel committed
365
366
        if (KMailSettings::self()->startSpecificFolderAtStartup()) {
            Akonadi::Collection::Id startupFolder = KMailSettings::self()->startupFolder();
Laurent Montel's avatar
Laurent Montel committed
367
            if (startupFolder > 0) {
Laurent Montel's avatar
Laurent Montel committed
368
                saver->restoreCurrentItem(QStringLiteral("c%1").arg(startupFolder));
Laurent Montel's avatar
Laurent Montel committed
369
            }
Laurent Montel's avatar
Laurent Montel committed
370
371
        }
    } else {
Laurent Montel's avatar
Laurent Montel committed
372
        saver->restoreCurrentItem(QStringLiteral("c%1").arg(id));
373
    }
Stephan Kulow's avatar
Stephan Kulow committed
374
375
376
377
378
}

//-----------------------------------------------------------------------------
//The kernel may have already been deleted when this method is called,
//perform all cleanup that requires the kernel in destruct()
379
KMMainWidget::~KMMainWidget()
Stephan Kulow's avatar
Stephan Kulow committed
380
{
Laurent Montel's avatar
Laurent Montel committed
381
382
    theMainWidgetList->removeAll(this);
    qDeleteAll(mFilterCommands);
Laurent Montel's avatar
Laurent Montel committed
383
    destruct();
Stephan Kulow's avatar
Stephan Kulow committed
384
385
386
387
}

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

Laurent Montel's avatar
Laurent Montel committed
405
406
407
408
409
    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
410

Laurent Montel's avatar
Laurent Montel committed
411
    mDestructed = true;
Stephan Kulow's avatar
Stephan Kulow committed
412
413
}

414
415
void KMMainWidget::clearCurrentFolder()
{
Laurent Montel's avatar
Laurent Montel committed
416
    mCurrentFolderSettings.clear();
417
418
419
    mCurrentCollection = Akonadi::Collection();
}

420
421
void KMMainWidget::slotStartCheckMail()
{
Laurent Montel's avatar
Laurent Montel committed
422
    if (mCheckMailTimer.isActive()) {
Laurent Montel's avatar
Laurent Montel committed
423
        mCheckMailTimer.stop();
Laurent Montel's avatar
Laurent Montel committed
424
    }
425
426
427
428
}

void KMMainWidget::slotEndCheckMail()
{
Laurent Montel's avatar
Laurent Montel committed
429
    if (!mCheckMailTimer.isActive()) {
Laurent Montel's avatar
Laurent Montel committed
430
        mCheckMailTimer.start();
Laurent Montel's avatar
Laurent Montel committed
431
    }
432
433
}

Laurent Montel's avatar
Laurent Montel committed
434
void KMMainWidget::slotUpdateActionsAfterMailChecking()
435
{
Laurent Montel's avatar
Laurent Montel committed
436
437
438
439
    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
440
    if (!kmkernel->isOffline() && (sendOnAll || sendOnManual)) {
Laurent Montel's avatar
Laurent Montel committed
441
442
443
444
445
        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();
446
447
}

448
449
450
void KMMainWidget::setCurrentCollection(const Akonadi::Collection &col)
{
    mCurrentCollection = col;
Laurent Montel's avatar
Laurent Montel committed
451
452
    if (mCurrentFolderSettings) {
        mCurrentFolderSettings->setCollection(col);
453
454
455
    }
}

Laurent Montel's avatar
Laurent Montel committed
456
void KMMainWidget::slotCollectionFetched(int collectionId)
457
{
Laurent Montel's avatar
Laurent Montel committed
458
459
460
    // 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.
461
    if (collectionId == mCurrentCollection.id()) {
462
        setCurrentCollection(CommonKernel->collectionFromId(mCurrentCollection.id()));
Laurent Montel's avatar
Laurent Montel committed
463
464
465
466
        updateMessageActions();
        updateFolderMenu();
    }
    // We call this for any collection, it could be one of our parents...
467
    if (mCurrentCollection.isValid()) {
468
        Q_EMIT captionChangeRequest(fullCollectionPath());
Laurent Montel's avatar
Laurent Montel committed
469
    }
470
471
}

472
473
474
475
476
477
478
QString KMMainWidget::fullCollectionPath() const
{
    if (mCurrentCollection.isValid()) {
        return MailCommon::Util::fullCollectionPath(mCurrentCollection);
    }
    return {};
}
479

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

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

    mGoToFirstUnreadMessageInSelectedFolder = false;
522
#ifndef QT_NO_CURSOR
523
    KPIM::KCursorSaver busy(KPIM::KBusyPtr::busy());
524
#endif
Laurent Montel's avatar
Laurent Montel committed
525

Laurent Montel's avatar
Laurent Montel committed
526
    if (mMsgView) {
Laurent Montel's avatar
Laurent Montel committed
527
        mMsgView->clear(true);
Laurent Montel's avatar
Laurent Montel committed
528
    }
529
    const bool newFolder = mCurrentCollection != col;
David Faure's avatar
David Faure committed
530

Laurent Montel's avatar
Laurent Montel committed
531
532
    // Delete any pending timer, if needed it will be recreated below
    delete mShowBusySplashTimer;
Laurent Montel's avatar
Laurent Montel committed
533
    mShowBusySplashTimer = nullptr;
Laurent Montel's avatar
Laurent Montel committed
534
    if (newFolder) {
Laurent Montel's avatar
Laurent Montel committed
535
536
537
        // We're changing folder: write configuration for the old one
        writeFolderConfig();
    }
Laurent Montel's avatar
Laurent Montel committed
538

Laurent Montel's avatar
Laurent Montel committed
539
    mCurrentFolderSettings = FolderSettings::forCollection(col);
540
    mCurrentCollection = col;
Laurent Montel's avatar
Laurent Montel committed
541

Laurent Montel's avatar
Laurent Montel committed
542
    readFolderConfig();
Laurent Montel's avatar
Laurent Montel committed
543
    if (mMsgView) {
544
        assignLoadExternalReference();
Laurent Montel's avatar
Laurent Montel committed
545
    }
Laurent Montel's avatar
Laurent Montel committed
546

Laurent Montel's avatar
Laurent Montel committed
547
    if (!mCurrentFolderSettings->isValid() && (mMessagePane->count() < 2)) {
Laurent Montel's avatar
Laurent Montel committed
548
        slotIntro();
549
550
551
552
    } else {
        if (mMessagePane->isHidden()) {
            mMessagePane->show();
        }
Laurent Montel's avatar
Laurent Montel committed
553
    }
Laurent Montel's avatar
Laurent Montel committed
554

Laurent Montel's avatar
Laurent Montel committed
555
556
557
    // 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.
558
    QTimer::singleShot(0, this, &KMMainWidget::slotShowSelectedFolderInPane);
559
560
}

Laurent Montel's avatar
Laurent Montel committed
561
void KMMainWidget::slotShowSelectedFolderInPane()
562
{
563
    if (mCurrentCollection.isValid()) {
564
565
        QModelIndex idx = Akonadi::EntityTreeModel::modelIndexForCollection(KMKernel::self()->entityTreeModel(), mCurrentCollection);
        mMessagePane->setCurrentFolder(mCurrentCollection, idx, false, mPreSelectionMode);
Laurent Montel's avatar
Laurent Montel committed
566
    }
Laurent Montel's avatar
Laurent Montel committed
567
568
    updateMessageActions();
    updateFolderMenu();
569
570
}

Stephan Kulow's avatar
Stephan Kulow committed
571
//-----------------------------------------------------------------------------
572
void KMMainWidget::readPreConfig()
Stephan Kulow's avatar
Stephan Kulow committed
573
{
Laurent Montel's avatar
Laurent Montel committed
574
575
576
    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
577

Laurent Montel's avatar
Laurent Montel committed
578
579
    mHtmlGlobalSetting = MessageViewer::MessageViewerSettings::self()->htmlMail();
    mHtmlLoadExtGlobalSetting = MessageViewer::MessageViewerSettings::self()->htmlLoadExternal();
Laurent Montel's avatar
Laurent Montel committed
580

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

584
    readFolderConfig();
Laurent Montel's avatar
Laurent Montel committed
585
    updateHtmlMenuEntry();
586
587
    if (mMsgView) {
        mMsgView->setDisplayFormatMessageOverwrite(mFolderDisplayFormatPreference);
Laurent Montel's avatar
Laurent Montel committed
588
        mMsgView->update(true);
589
    }
Stephan Kulow's avatar
Stephan Kulow committed
590
591
592
}

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

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

631
632
633
//-----------------------------------------------------------------------------
void KMMainWidget::layoutSplitters()
{
Laurent Montel's avatar
Laurent Montel committed
634
    // This function can only be called when the old splitters are already deleted
Laurent Montel's avatar
Laurent Montel committed
635
636
    Q_ASSERT(!mSplitter1);
    Q_ASSERT(!mSplitter2);
637

Laurent Montel's avatar
Laurent Montel committed
638
639
    // 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
640
    if (mMsgView) {
Laurent Montel's avatar
Laurent Montel committed
641
642
        disconnect(mMsgView->copyAction(), &QAction::triggered,
                   mMsgView, &KMReaderWin::slotCopySelectedText);
Laurent Montel's avatar
Laurent Montel committed
643
    }
Laurent Montel's avatar
Laurent Montel committed
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658

    // 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
659
660
    mSplitter1 = new QSplitter(this);
    mSplitter2 = new QSplitter(mSplitter1);
Laurent Montel's avatar
Laurent Montel committed
661

662
    QWidget *folderTreeWidget = mFolderTreeWidget;
Laurent Montel's avatar
Laurent Montel committed
663
664
    if (mFavoriteCollectionsView) {
        mFolderViewSplitter = new QSplitter(Qt::Vertical);
Laurent Montel's avatar
Laurent Montel committed
665
        mFolderViewSplitter->setChildrenCollapsible(false);
Laurent Montel's avatar
Laurent Montel committed
666
        mFolderViewSplitter->addWidget(mFavoriteCollectionsView);
667
        mFolderViewSplitter->addWidget(mFolderTreeWidget);
Laurent Montel's avatar
Laurent Montel committed
668
        folderTreeWidget = mFolderViewSplitter;
Till Adam's avatar
Till Adam committed
669
    }
670

Laurent Montel's avatar
Laurent Montel committed
671
    if (mLongFolderList) {
Laurent Montel's avatar
Laurent Montel committed
672
        // add folder tree
Laurent Montel's avatar
Laurent Montel committed
673
674
        mSplitter1->setOrientation(Qt::Horizontal);
        mSplitter1->addWidget(folderTreeWidget);
Laurent Montel's avatar
Laurent Montel committed
675
676

        // and the rest to the right
Laurent Montel's avatar
Laurent Montel committed
677
        mSplitter1->addWidget(mSplitter2);
Laurent Montel's avatar
Laurent Montel committed
678
679

        // add the message list to the right or below
Laurent Montel's avatar
Laurent Montel committed
680
681
        if (readerWindowAtSide) {
            mSplitter2->setOrientation(Qt::Horizontal);
Laurent Montel's avatar
Laurent Montel committed
682
        } else {
Laurent Montel's avatar
Laurent Montel committed
683
            mSplitter2->setOrientation(Qt::Vertical);
Laurent Montel's avatar
Laurent Montel committed
684
        }
Laurent Montel's avatar
Laurent Montel committed
685
        mSplitter2->addWidget(mMessagePane);
Laurent Montel's avatar
Laurent Montel committed
686
687

        // add the preview window, if there is one
Laurent Montel's avatar
Laurent Montel committed
688
689
        if (mMsgView) {
            mSplitter2->addWidget(mMsgView);
Laurent Montel's avatar
Laurent Montel committed
690
691
        }
    } else { // short folder list
Laurent Montel's avatar
Laurent Montel committed
692
693
694
        if (mReaderWindowBelow) {
            mSplitter1->setOrientation(Qt::Vertical);
            mSplitter2->setOrientation(Qt::Horizontal);
Laurent Montel's avatar
Laurent Montel committed
695
        } else { // at side or none
Laurent Montel's avatar
Laurent Montel committed
696
697
            mSplitter1->setOrientation(Qt::Horizontal);
            mSplitter2->setOrientation(Qt::Vertical);
Laurent Montel's avatar
Laurent Montel committed
698
699
        }

Laurent Montel's avatar
Laurent Montel committed
700
        mSplitter1->addWidget(mSplitter2);
Laurent Montel's avatar
Laurent Montel committed
701
702

        // add folder tree
Laurent Montel's avatar
Laurent Montel committed
703
        mSplitter2->addWidget(folderTreeWidget);
Laurent Montel's avatar
Laurent Montel committed
704
        // add message list to splitter 2
Laurent Montel's avatar
Laurent Montel committed
705
        mSplitter2->addWidget(mMessagePane);
Laurent Montel's avatar
Laurent Montel committed
706
707

        // add the preview window, if there is one
Laurent Montel's avatar
Laurent Montel committed
708
709
710
        if (mMsgView) {
            mSplitter1->addWidget(mMsgView);
        }
Till Adam's avatar
Till Adam committed
711
    }
712

Laurent Montel's avatar
Laurent Montel committed
713
714
715
    //
    // Set splitter properties
    //
Laurent Montel's avatar
Laurent Montel committed
716
    mSplitter1->setObjectName(QStringLiteral("splitter1"));
Laurent Montel's avatar
Laurent Montel committed
717
    mSplitter1->setChildrenCollapsible(false);
Laurent Montel's avatar
Laurent Montel committed
718
    mSplitter2->setObjectName(QStringLiteral("splitter2"));
Laurent Montel's avatar
Laurent Montel committed
719
    mSplitter2->setChildrenCollapsible(false);
Laurent Montel's avatar
Laurent Montel committed
720
721
722
723

    //
    // Set the stretch factors
    //
Laurent Montel's avatar
Laurent Montel committed
724
725
726
727
    mSplitter1->setStretchFactor(0, 0);
    mSplitter2->setStretchFactor(0, 0);
    mSplitter1->setStretchFactor(1, 1);
    mSplitter2->setStretchFactor(1, 1);
Laurent Montel's avatar
Laurent Montel committed
728

Laurent Montel's avatar
Laurent Montel committed
729
730
731
    if (mFavoriteCollectionsView) {
        mFolderViewSplitter->setStretchFactor(0, 0);
        mFolderViewSplitter->setStretchFactor(1, 1);
Laurent Montel's avatar
Laurent Montel committed
732
    }
733

Laurent Montel's avatar
Laurent Montel committed
734
735
736
    // 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
737
738
739
    if (readerWindowAtSide && !mLongFolderList) {
        mSplitter1->setStretchFactor(0, 1);
        mSplitter1->setStretchFactor(1, 0);
Laurent Montel's avatar
Laurent Montel committed
740
    }
741

Laurent Montel's avatar
Laurent Montel committed
742
743
744
745
746
747
    //
    // 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
748
749
750
751
752
753
    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
754

Laurent Montel's avatar
Laurent Montel committed
755
    int ffvHeight = mFolderViewSplitter ? KMKernel::self()->mailCommonSettings()->favoriteCollectionViewHeight() : 0;
Laurent Montel's avatar
Laurent Montel committed
756
757

    // If the message viewer was hidden before, make sure it is not zero height
Laurent Montel's avatar
Laurent Montel committed
758
    if (messageViewerHeight < 10 && readerWindowBelow) {
Laurent Montel's avatar
Laurent Montel committed
759
760
        headerHeight /= 2;
        messageViewerHeight = headerHeight;
761
    }
Laurent Montel's avatar
Laurent Montel committed
762

Laurent Montel's avatar
Laurent Montel committed
763
764
    if (mLongFolderList) {
        if (!readerWindowAtSide) {
Laurent Montel's avatar
Laurent Montel committed
765
766
767
            splitter1Sizes << folderViewWidth << headerWidth;
            splitter2Sizes << headerHeight << messageViewerHeight;
        } else {
Laurent Montel's avatar
Laurent Montel committed
768
            splitter1Sizes << folderViewWidth << (headerWidth + messageViewerWidth);
Laurent Montel's avatar
Laurent Montel committed
769
770
            splitter2Sizes << headerWidth << messageViewerWidth;
        }
771
    } else {
Laurent Montel's avatar
Laurent Montel committed
772
        if (!readerWindowAtSide) {
Laurent Montel's avatar
Laurent Montel committed
773
774
775
776
777
778
            splitter1Sizes << headerHeight << messageViewerHeight;
            splitter2Sizes << folderViewWidth << headerWidth;
        } else {
            splitter1Sizes << headerWidth << messageViewerWidth;
            splitter2Sizes << ftHeight + ffvHeight << messageViewerHeight;
        }
779
780
    }

Laurent Montel's avatar
Laurent Montel committed
781
782
    mSplitter1->setSizes(splitter1Sizes);
    mSplitter2->setSizes(splitter2Sizes);
783

Laurent Montel's avatar
Laurent Montel committed
784
    if (mFolderViewSplitter) {
Laurent Montel's avatar
Laurent Montel committed
785
786
        QList<int> splitterSizes;
        splitterSizes << ffvHeight << ftHeight;
Laurent Montel's avatar
Laurent Montel committed
787
        mFolderViewSplitter->setSizes(splitterSizes);
Laurent Montel's avatar
Laurent Montel committed
788
    }
789

Laurent Montel's avatar
Laurent Montel committed
790
791
792
    //
    // Now add the splitters to the main layout
    //
Laurent Montel's avatar
Laurent Montel committed
793
    mTopLayout->addWidget(mSplitter1);
794

Laurent Montel's avatar
Laurent Montel committed
795
796
797
798
799
    // 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
800

Laurent Montel's avatar
Laurent Montel committed
801
    // By default hide th unread and size columns on first run.
Laurent Montel's avatar
Laurent Montel committed
802
803
804
    if (kmkernel->firstStart()) {
        mFolderTreeWidget->folderTreeView()->hideColumn(1);
        mFolderTreeWidget->folderTreeView()->hideColumn(3);
Laurent Montel's avatar
Laurent Montel committed
805
        mFolderTreeWidget->folderTreeView()->header()->resizeSection(0, static_cast<int>(folderViewWidth * 0.8));
Laurent Montel's avatar
Laurent Montel committed
806
    }
807

Laurent Montel's avatar
Laurent Montel committed
808
    // Make the copy action work, see disconnect comment above
Laurent Montel's avatar
Laurent Montel committed
809
    if (mMsgView) {
Laurent Montel's avatar
Laurent Montel committed
810
811
        connect(mMsgView->copyAction(), &QAction::triggered,
                mMsgView, &KMReaderWin::slotCopySelectedText);
Laurent Montel's avatar
Laurent Montel committed
812
    }
813
}
Stephan Kulow's avatar
Stephan Kulow committed
814

815
816
817
//-----------------------------------------------------------------------------
void KMMainWidget::refreshFavoriteFoldersViewProperties()
{
Laurent Montel's avatar
Laurent Montel committed
818
    if (mFavoriteCollectionsView) {
Laurent Montel's avatar
Laurent Montel committed
819
        if (KMKernel::self()->mailCommonSettings()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode) {
Laurent Montel's avatar
Laurent Montel committed
820
            mFavoriteCollectionsView->changeViewMode(QListView::IconMode);
Laurent Montel's avatar
Laurent Montel committed
821
        } else if (KMKernel::self()->mailCommonSettings()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode) {
Laurent Montel's avatar
Laurent Montel committed
822
823
824
825
826
827
            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
828
829
        mFavoriteCollectionsView->updateMode();
    }
830
831
}

Stephan Kulow's avatar
Stephan Kulow committed
832
//-----------------------------------------------------------------------------
833
void KMMainWidget::readConfig()
Stephan Kulow's avatar
Stephan Kulow committed
834
{
Laurent Montel's avatar
Laurent Montel committed
835
836
837
838
    const bool oldLongFolderList = mLongFolderList;
    const bool oldReaderWindowActive = mReaderWindowActive;
    const bool oldReaderWindowBelow = mReaderWindowBelow;
    const bool oldFavoriteFolderView = mEnableFavoriteFolderView;
839
    const bool oldFolderQuickSearch = mEnableFolderQuickSearch;
840

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

Laurent Montel's avatar
Laurent Montel committed
844
    if (mStartupDone) {
Laurent Montel's avatar
Laurent Montel committed
845
846
        readPreConfig();

Laurent Montel's avatar
Laurent Montel committed
847
848
849
850
        layoutChanged = (oldLongFolderList != mLongFolderList)
                        || (oldReaderWindowActive != mReaderWindowActive)
                        || (oldReaderWindowBelow != mReaderWindowBelow)
                        || (oldFavoriteFolderView != mEnableFavoriteFolderView);
Laurent Montel's avatar
Laurent Montel committed
851

Laurent Montel's avatar
Laurent Montel committed
852
        if (layoutChanged) {
Laurent Montel's avatar