configureappearancepage.cpp 55 KB
Newer Older
Laurent Montel's avatar
Laurent Montel committed
1
/*
Laurent Montel's avatar
Laurent Montel committed
2
  Copyright (c) 2013-2020 Laurent Montel <montel@kde.org>
Laurent Montel's avatar
Laurent Montel committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

  This program 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.

  This program 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
*/

#include "configureappearancepage.h"
Laurent Montel's avatar
Laurent Montel committed
19
#include <PimCommon/ConfigureImmutableWidgetUtils>
20
using namespace PimCommon::ConfigureImmutableWidgetUtils;
Laurent Montel's avatar
Laurent Montel committed
21
#include "configuredialog/colorlistbox.h"
Laurent Montel's avatar
Laurent Montel committed
22
23
24
25
#include <MessageList/AggregationComboBox>
#include <MessageList/AggregationConfigButton>
#include <MessageList/ThemeComboBox>
#include <MessageList/ThemeConfigButton>
Laurent Montel's avatar
Laurent Montel committed
26
#include <Libkdepim/LineEditCatchReturnKey>
Laurent Montel's avatar
Laurent Montel committed
27
#include "messagelistsettings.h"
Laurent Montel's avatar
Laurent Montel committed
28
#include <MailCommon/TagWidget>
Laurent Montel's avatar
Laurent Montel committed
29
#include "MailCommon/Tag"
Laurent Montel's avatar
Laurent Montel committed
30
#include "kmkernel.h"
31

Laurent Montel's avatar
Laurent Montel committed
32
#include "util.h"
Laurent Montel's avatar
Laurent Montel committed
33
#include <MailCommon/FolderTreeWidget>
Laurent Montel's avatar
Laurent Montel committed
34
35
36

#include "kmmainwidget.h"

Laurent Montel's avatar
Laurent Montel committed
37
#include "mailcommonsettings_base.h"
Laurent Montel's avatar
Laurent Montel committed
38

Laurent Montel's avatar
Laurent Montel committed
39
40
#include <MessageViewer/ConfigureWidget>
#include <MessageViewer/MessageViewerSettings>
Laurent Montel's avatar
Laurent Montel committed
41

Laurent Montel's avatar
Laurent Montel committed
42
#include <MessageList/MessageListUtil>
Laurent Montel's avatar
Laurent Montel committed
43
#include <MessageCore/MessageCoreSettings>
Laurent Montel's avatar
Laurent Montel committed
44
#include <MessageCore/MessageCoreUtil>
Laurent Montel's avatar
Laurent Montel committed
45
#include "settings/kmailsettings.h"
Laurent Montel's avatar
Laurent Montel committed
46

Laurent Montel's avatar
Laurent Montel committed
47
#include <MailCommon/MailUtil>
Laurent Montel's avatar
Laurent Montel committed
48

Laurent Montel's avatar
Laurent Montel committed
49
#include <AkonadiCore/Tag>
Laurent Montel's avatar
Laurent Montel committed
50
51
#include <AkonadiCore/TagFetchJob>
#include <AkonadiCore/TagFetchScope>
Laurent Montel's avatar
Laurent Montel committed
52
53
#include <AkonadiCore/TagDeleteJob>
#include <AkonadiCore/TagCreateJob>
Laurent Montel's avatar
Laurent Montel committed
54
#include <AkonadiCore/TagAttribute>
Laurent Montel's avatar
Laurent Montel committed
55
#include <AkonadiCore/TagModifyJob>
56

Laurent Montel's avatar
Laurent Montel committed
57
#include <KIconButton>
Laurent Montel's avatar
Laurent Montel committed
58
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
59
60
61
#include <KColorScheme>
#include <KSeparator>
#include <KFontChooser>
Laurent Montel's avatar
Laurent Montel committed
62
#include <QHBoxLayout>
Laurent Montel's avatar
Laurent Montel committed
63
#include <KMessageBox>
Laurent Montel's avatar
Laurent Montel committed
64
#include <KKeySequenceWidget>
Laurent Montel's avatar
Laurent Montel committed
65
#include <QLineEdit>
Laurent Montel's avatar
Laurent Montel committed
66
#include <QIcon>
Laurent Montel's avatar
Laurent Montel committed
67
#include "kmail_debug.h"
Laurent Montel's avatar
Laurent Montel committed
68

Laurent Montel's avatar
Laurent Montel committed
69
#include <kmime/kmime_dateformatter.h>
Laurent Montel's avatar
Laurent Montel committed
70
71
72
using KMime::DateFormatter;

#include <QWhatsThis>
73
74
75
#include <QButtonGroup>
#include <QSpinBox>
#include <QLabel>
Laurent Montel's avatar
Laurent Montel committed
76
#include <QFontDatabase>
Volker Krause's avatar
Volker Krause committed
77
#include <QGroupBox>
Sandro Knauß's avatar
Sandro Knauß committed
78
79
80
#include <QVBoxLayout>
#include <QRadioButton>
#include <QCheckBox>
Laurent Montel's avatar
Laurent Montel committed
81
82
83
84
using namespace MailCommon;

QString AppearancePage::helpAnchor() const
{
Laurent Montel's avatar
Laurent Montel committed
85
    return QStringLiteral("configure-appearance");
Laurent Montel's avatar
Laurent Montel committed
86
87
}

Laurent Montel's avatar
Laurent Montel committed
88
89
AppearancePage::AppearancePage(QWidget *parent)
    : ConfigModuleWithTabs(parent)
Laurent Montel's avatar
Laurent Montel committed
90
{
Laurent Montel's avatar
Laurent Montel committed
91
92
93
94
95
96
97
    //
    // "General" tab:
    //
    ReaderTab *readerTab = new ReaderTab();
    addTab(readerTab, i18n("General"));
    addConfig(MessageViewer::MessageViewerSettings::self(), readerTab);

Laurent Montel's avatar
Laurent Montel committed
98
99
100
    //
    // "Fonts" tab:
    //
101
102
    FontsTab *fontsTab = new FontsTab();
    addTab(fontsTab, i18n("Fonts"));
Laurent Montel's avatar
Laurent Montel committed
103
104
105
106

    //
    // "Colors" tab:
    //
107
108
    ColorsTab *colorsTab = new ColorsTab();
    addTab(colorsTab, i18n("Colors"));
Laurent Montel's avatar
Laurent Montel committed
109
110
111
112

    //
    // "Layout" tab:
    //
113
114
    LayoutTab *layoutTab = new LayoutTab();
    addTab(layoutTab, i18n("Layout"));
Laurent Montel's avatar
Laurent Montel committed
115
116
117
118

    //
    // "Headers" tab:
    //
119
120
    HeadersTab *headersTab = new HeadersTab();
    addTab(headersTab, i18n("Message List"));
Laurent Montel's avatar
Laurent Montel committed
121
122
123
124

    //
    // "Message Tag" tab:
    //
125
126
    MessageTagTab *messageTagTab = new MessageTagTab();
    addTab(messageTagTab, i18n("Message Tags"));
Laurent Montel's avatar
Laurent Montel committed
127
128
129
130
}

QString AppearancePage::FontsTab::helpAnchor() const
{
Laurent Montel's avatar
Laurent Montel committed
131
    return QStringLiteral("configure-appearance-fonts");
Laurent Montel's avatar
Laurent Montel committed
132
133
134
}

static const struct {
Laurent Montel's avatar
Laurent Montel committed
135
136
    const char *configName;
    const char *displayName;
Laurent Montel's avatar
Laurent Montel committed
137
138
    bool enableFamilyAndSize;
    bool onlyFixed;
Laurent Montel's avatar
Laurent Montel committed
139
140
141
} fontNames[] = {
    { "body-font", I18N_NOOP("Message Body"), true, false },
    { "MessageListFont", I18N_NOOP("Message List"), true, false },
142
143
144
    { "UnreadMessageFont", I18N_NOOP("Message List - Unread Messages"), false, false },
    { "ImportantMessageFont", I18N_NOOP("Message List - Important Messages"), false, false },
    { "TodoMessageFont", I18N_NOOP("Message List - Action Item Messages"), false, false },
Laurent Montel's avatar
Laurent Montel committed
145
146
    { "fixed-font", I18N_NOOP("Fixed Width Font"), true, true },
    { "composer-font", I18N_NOOP("Composer"), true, false },
Laurent Montel's avatar
Laurent Montel committed
147
    { "print-font", I18N_NOOP("Printing Output"), true, false },
Laurent Montel's avatar
Laurent Montel committed
148
};
Laurent Montel's avatar
Laurent Montel committed
149
static const int numFontNames = sizeof fontNames / sizeof *fontNames;
Laurent Montel's avatar
Laurent Montel committed
150

Laurent Montel's avatar
Laurent Montel committed
151
AppearancePageFontsTab::AppearancePageFontsTab(QWidget *parent)
Laurent Montel's avatar
Laurent Montel committed
152
153
    : ConfigModuleTab(parent)
    , mActiveFontIndex(-1)
Laurent Montel's avatar
Laurent Montel committed
154
{
Laurent Montel's avatar
Laurent Montel committed
155
    assert(numFontNames == sizeof mFont / sizeof *mFont);
Laurent Montel's avatar
Laurent Montel committed
156
157

    // "Use custom fonts" checkbox, followed by <hr>
Laurent Montel's avatar
Laurent Montel committed
158
159
160
161
    QVBoxLayout *vlay = new QVBoxLayout(this);
    mCustomFontCheck = new QCheckBox(i18n("&Use custom fonts"), this);
    vlay->addWidget(mCustomFontCheck);
    vlay->addWidget(new KSeparator(Qt::Horizontal, this));
162
163
    connect(mCustomFontCheck, &QCheckBox::stateChanged,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
164
165

    // "font location" combo box and label:
Laurent Montel's avatar
Laurent Montel committed
166
    QHBoxLayout *hlay = new QHBoxLayout(); // inherites spacing
Laurent Montel's avatar
Laurent Montel committed
167
    vlay->addLayout(hlay);
Laurent Montel's avatar
Laurent Montel committed
168
    mFontLocationCombo = new QComboBox(this);
Laurent Montel's avatar
Laurent Montel committed
169
    mFontLocationCombo->setEnabled(false);   // !mCustomFontCheck->isChecked()
Laurent Montel's avatar
Laurent Montel committed
170
171

    QStringList fontDescriptions;
172
    fontDescriptions.reserve(numFontNames);
Laurent Montel's avatar
Laurent Montel committed
173
    for (int i = 0; i < numFontNames; ++i) {
Laurent Montel's avatar
Laurent Montel committed
174
175
176
        fontDescriptions << i18n(fontNames[i].displayName);
    }
    mFontLocationCombo->addItems(fontDescriptions);
Laurent Montel's avatar
Laurent Montel committed
177

Laurent Montel's avatar
Laurent Montel committed
178
179
180
181
    QLabel *label = new QLabel(i18n("Apply &to:"), this);
    label->setBuddy(mFontLocationCombo);
    label->setEnabled(false);   // since !mCustomFontCheck->isChecked()
    hlay->addWidget(label);
Laurent Montel's avatar
Laurent Montel committed
182

Laurent Montel's avatar
Laurent Montel committed
183
184
185
186
187
188
    hlay->addWidget(mFontLocationCombo);
    hlay->addStretch(10);
    mFontChooser = new KFontChooser(this, KFontChooser::DisplayFrame,
                                    QStringList(), 4);
    mFontChooser->setEnabled(false);   // since !mCustomFontCheck->isChecked()
    vlay->addWidget(mFontChooser);
189
190
    connect(mFontChooser, &KFontChooser::fontSelected,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
191
192

    // {en,dis}able widgets depending on the state of mCustomFontCheck:
193
194
195
196
197
198
    connect(mCustomFontCheck, &QAbstractButton::toggled,
            label, &QWidget::setEnabled);
    connect(mCustomFontCheck, &QAbstractButton::toggled,
            mFontLocationCombo, &QWidget::setEnabled);
    connect(mCustomFontCheck, &QAbstractButton::toggled,
            mFontChooser, &QWidget::setEnabled);
Laurent Montel's avatar
Laurent Montel committed
199
    // load the right font settings into mFontChooser:
Laurent Montel's avatar
Laurent Montel committed
200
    connect(mFontLocationCombo, qOverload<int>(&QComboBox::activated),
201
            this, &AppearancePage::FontsTab::slotFontSelectorChanged);
Laurent Montel's avatar
Laurent Montel committed
202
203
}

Laurent Montel's avatar
Laurent Montel committed
204
void AppearancePage::FontsTab::slotFontSelectorChanged(int index)
Laurent Montel's avatar
Laurent Montel committed
205
{
Laurent Montel's avatar
Laurent Montel committed
206
    qCDebug(KMAIL_LOG) << "slotFontSelectorChanged() called";
Laurent Montel's avatar
Laurent Montel committed
207
208
209
    if (index < 0 || index >= mFontLocationCombo->count()) {
        return;    // Should never happen, but it is better to check.
    }
Laurent Montel's avatar
Laurent Montel committed
210
211

    // Save current fontselector setting before we install the new:
Laurent Montel's avatar
Laurent Montel committed
212
    if (mActiveFontIndex == 0) {
Laurent Montel's avatar
Laurent Montel committed
213
        mFont[0] = mFontChooser->font();
214
        // hardcode the family and size of "message body" dependent fonts:
Laurent Montel's avatar
Laurent Montel committed
215
        for (int i = 0; i < numFontNames; ++i) {
Laurent Montel's avatar
Laurent Montel committed
216
            if (!fontNames[i].enableFamilyAndSize) {
Laurent Montel's avatar
Laurent Montel committed
217
218
219
                // ### shall we copy the font and set the save and re-set
                // {regular,italic,bold,bold italic} property or should we
                // copy only family and pointSize?
Laurent Montel's avatar
Laurent Montel committed
220
                mFont[i].setFamily(mFont[0].family());
Laurent Montel's avatar
Laurent Montel committed
221
                mFont[i].setPointSize/*Float?*/ (mFont[0].pointSize/*Float?*/ ());
Laurent Montel's avatar
Laurent Montel committed
222
            }
Laurent Montel's avatar
Laurent Montel committed
223
        }
Laurent Montel's avatar
Laurent Montel committed
224
    } else if (mActiveFontIndex > 0) {
Laurent Montel's avatar
Laurent Montel committed
225
        mFont[ mActiveFontIndex ] = mFontChooser->font();
Laurent Montel's avatar
Laurent Montel committed
226
    }
Laurent Montel's avatar
Laurent Montel committed
227
228
229
    mActiveFontIndex = index;

    // Disonnect so the "Apply" button is not activated by the change
230
231
    disconnect(mFontChooser, &KFontChooser::fontSelected,
               this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
232
233

    // Display the new setting:
Laurent Montel's avatar
Laurent Montel committed
234
    mFontChooser->setFont(mFont[index], fontNames[index].onlyFixed);
Laurent Montel's avatar
Laurent Montel committed
235

236
237
    connect(mFontChooser, &KFontChooser::fontSelected,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
238
239

    // Disable Family and Size list if we have selected a quote font:
Laurent Montel's avatar
Laurent Montel committed
240
241
    mFontChooser->enableColumn(KFontChooser::FamilyList | KFontChooser::SizeList,
                               fontNames[ index ].enableFamilyAndSize);
Laurent Montel's avatar
Laurent Montel committed
242
243
244
245
}

void AppearancePage::FontsTab::doLoadOther()
{
246
    if (KMKernel::self()) {
Laurent Montel's avatar
Laurent Montel committed
247
        KConfigGroup fonts(KMKernel::self()->config(), "Fonts");
248

Laurent Montel's avatar
Laurent Montel committed
249
250
        mFont[0] = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
        QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
251

Laurent Montel's avatar
Laurent Montel committed
252
        for (int i = 0; i < numFontNames; ++i) {
253
            const QString configName = QLatin1String(fontNames[i].configName);
254
            if (configName == QLatin1String("MessageListFont")) {
Laurent Montel's avatar
Laurent Montel committed
255
                mFont[i] = MessageList::MessageListSettings::self()->messageListFont();
256
            } else if (configName == QLatin1String("UnreadMessageFont")) {
Laurent Montel's avatar
Laurent Montel committed
257
                mFont[i] = MessageList::MessageListSettings::self()->unreadMessageFont();
258
            } else if (configName == QLatin1String("ImportantMessageFont")) {
Laurent Montel's avatar
Laurent Montel committed
259
                mFont[i] = MessageList::MessageListSettings::self()->importantMessageFont();
260
            } else if (configName == QLatin1String("TodoMessageFont")) {
Laurent Montel's avatar
Laurent Montel committed
261
                mFont[i] = MessageList::MessageListSettings::self()->todoMessageFont();
262
            } else {
Laurent Montel's avatar
Laurent Montel committed
263
264
                mFont[i] = fonts.readEntry(configName,
                                           (fontNames[i].onlyFixed) ? fixedFont : mFont[0]);
265
            }
Laurent Montel's avatar
Laurent Montel committed
266
        }
Laurent Montel's avatar
Laurent Montel committed
267
        mCustomFontCheck->setChecked(!MessageCore::MessageCoreSettings::self()->useDefaultFonts());
Laurent Montel's avatar
Laurent Montel committed
268
269
        mFontLocationCombo->setCurrentIndex(0);
        slotFontSelectorChanged(0);
270
271
    } else {
        setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
272
273
274
275
276
    }
}

void AppearancePage::FontsTab::save()
{
277
    if (KMKernel::self()) {
Laurent Montel's avatar
Laurent Montel committed
278
        KConfigGroup fonts(KMKernel::self()->config(), "Fonts");
279
280

        // read the current font (might have been modified)
Laurent Montel's avatar
Laurent Montel committed
281
        if (mActiveFontIndex >= 0) {
282
            mFont[ mActiveFontIndex ] = mFontChooser->font();
Laurent Montel's avatar
Laurent Montel committed
283
        }
284
285

        const bool customFonts = mCustomFontCheck->isChecked();
Laurent Montel's avatar
Laurent Montel committed
286
        MessageCore::MessageCoreSettings::self()->setUseDefaultFonts(!customFonts);
287

Laurent Montel's avatar
Laurent Montel committed
288
        for (int i = 0; i < numFontNames; ++i) {
289
            const QString configName = QLatin1String(fontNames[i].configName);
290
            if (customFonts && configName == QLatin1String("MessageListFont")) {
Laurent Montel's avatar
Laurent Montel committed
291
                MessageList::MessageListSettings::self()->setMessageListFont(mFont[i]);
292
            } else if (customFonts && configName == QLatin1String("UnreadMessageFont")) {
Laurent Montel's avatar
Laurent Montel committed
293
                MessageList::MessageListSettings::self()->setUnreadMessageFont(mFont[i]);
294
            } else if (customFonts && configName == QLatin1String("ImportantMessageFont")) {
Laurent Montel's avatar
Laurent Montel committed
295
                MessageList::MessageListSettings::self()->setImportantMessageFont(mFont[i]);
296
            } else if (customFonts && configName == QLatin1String("TodoMessageFont")) {
Laurent Montel's avatar
Laurent Montel committed
297
                MessageList::MessageListSettings::self()->setTodoMessageFont(mFont[i]);
298
            } else {
Laurent Montel's avatar
Laurent Montel committed
299
                if (customFonts || fonts.hasKey(configName)) {
300
301
                    // Don't write font info when we use default fonts, but write
                    // if it's already there:
Laurent Montel's avatar
Laurent Montel committed
302
303
                    fonts.writeEntry(configName, mFont[i]);
                }
Laurent Montel's avatar
Laurent Montel committed
304
305
306
307
308
309
310
            }
        }
    }
}

void AppearancePage::FontsTab::doResetToDefaultsOther()
{
Laurent Montel's avatar
Laurent Montel committed
311
    mCustomFontCheck->setChecked(false);
Laurent Montel's avatar
Laurent Montel committed
312
313
314
315
}

QString AppearancePage::ColorsTab::helpAnchor() const
{
Laurent Montel's avatar
Laurent Montel committed
316
    return QStringLiteral("configure-appearance-colors");
Laurent Montel's avatar
Laurent Montel committed
317
318
319
}

static const struct {
Laurent Montel's avatar
Laurent Montel committed
320
321
    const char *configName;
    const char *displayName;
Laurent Montel's avatar
Laurent Montel committed
322
} colorNames[] = { // adjust doLoadOther if you change this:
Laurent Montel's avatar
Laurent Montel committed
323
324
325
326
327
328
329
330
331
    { "QuotedText1", I18N_NOOP("Quoted Text - First Level") },
    { "QuotedText2", I18N_NOOP("Quoted Text - Second Level") },
    { "QuotedText3", I18N_NOOP("Quoted Text - Third Level") },
    { "LinkColor", I18N_NOOP("Link") },
    { "UnreadMessageColor", I18N_NOOP("Unread Message") },
    { "ImportantMessageColor", I18N_NOOP("Important Message") },
    { "TodoMessageColor", I18N_NOOP("Action Item Message") },
    { "ColorbarBackgroundPlain", I18N_NOOP("HTML Status Bar Background - No HTML Message") },
    { "ColorbarForegroundPlain", I18N_NOOP("HTML Status Bar Foreground - No HTML Message") },
Laurent Montel's avatar
Laurent Montel committed
332
333
    { "ColorbarBackgroundHTML", I18N_NOOP("HTML Status Bar Background - HTML Message") },
    { "ColorbarForegroundHTML", I18N_NOOP("HTML Status Bar Foreground - HTML Message") }
Laurent Montel's avatar
Laurent Montel committed
334
};
Laurent Montel's avatar
Laurent Montel committed
335
static const int numColorNames = sizeof colorNames / sizeof *colorNames;
Laurent Montel's avatar
Laurent Montel committed
336
337
338

AppearancePageColorsTab::AppearancePageColorsTab(QWidget *parent)
    : ConfigModuleTab(parent)
Laurent Montel's avatar
Laurent Montel committed
339
340
{
    // "use custom colors" check box
Laurent Montel's avatar
Laurent Montel committed
341
342
343
    QVBoxLayout *vlay = new QVBoxLayout(this);
    mCustomColorCheck = new QCheckBox(i18n("&Use custom colors"), this);
    vlay->addWidget(mCustomColorCheck);
344
345
    connect(mCustomColorCheck, &QCheckBox::stateChanged,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
346

Laurent Montel's avatar
Laurent Montel committed
347
    mUseInlineStyle = new QCheckBox(i18n("&Do not change color from original HTML mail"), this);
348
349
350
351
    vlay->addWidget(mUseInlineStyle);
    connect(mUseInlineStyle, &QCheckBox::stateChanged,
            this, &ConfigModuleTab::slotEmitChanged);

Laurent Montel's avatar
Laurent Montel committed
352
    // color list box:
Laurent Montel's avatar
Laurent Montel committed
353
354
    mColorList = new ColorListBox(this);
    mColorList->setEnabled(false);   // since !mCustomColorCheck->isChecked()
Laurent Montel's avatar
Laurent Montel committed
355
    for (int i = 0; i < numColorNames; ++i) {
Laurent Montel's avatar
Laurent Montel committed
356
357
358
        mColorList->addColor(i18n(colorNames[i].displayName));
    }
    vlay->addWidget(mColorList, 1);
Laurent Montel's avatar
Laurent Montel committed
359
360

    // "recycle colors" check box:
Laurent Montel's avatar
Laurent Montel committed
361
362
    mRecycleColorCheck
        = new QCheckBox(i18n("Recycle colors on deep &quoting"), this);
Laurent Montel's avatar
Laurent Montel committed
363
364
    mRecycleColorCheck->setEnabled(false);
    vlay->addWidget(mRecycleColorCheck);
365
366
    connect(mRecycleColorCheck, &QCheckBox::stateChanged,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
367
368
369

    // close to quota threshold
    QHBoxLayout *hbox = new QHBoxLayout();
Laurent Montel's avatar
Laurent Montel committed
370
371
372
373
374
375
    vlay->addLayout(hbox);
    QLabel *l = new QLabel(i18n("Close to quota threshold:"), this);
    hbox->addWidget(l);
    mCloseToQuotaThreshold = new QSpinBox(this);
    mCloseToQuotaThreshold->setRange(0, 100);
    mCloseToQuotaThreshold->setSingleStep(1);
Laurent Montel's avatar
Laurent Montel committed
376
    connect(mCloseToQuotaThreshold, qOverload<int>(&QSpinBox::valueChanged),
377
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
378
379
380
381
    mCloseToQuotaThreshold->setSuffix(i18n("%"));

    hbox->addWidget(mCloseToQuotaThreshold);
    hbox->addWidget(new QWidget(this), 2);
Laurent Montel's avatar
Laurent Montel committed
382
383

    // {en,dir}able widgets depending on the state of mCustomColorCheck:
384
385
386
387
388
389
390
391
    connect(mCustomColorCheck, &QAbstractButton::toggled,
            mColorList, &QWidget::setEnabled);
    connect(mCustomColorCheck, &QAbstractButton::toggled,
            mRecycleColorCheck, &QWidget::setEnabled);
    connect(mCustomColorCheck, &QCheckBox::stateChanged,
            this, &ConfigModuleTab::slotEmitChanged);
    connect(mColorList, &ColorListBox::changed,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
392
393
394
395
}

void AppearancePage::ColorsTab::doLoadOther()
{
Laurent Montel's avatar
Laurent Montel committed
396
    mCustomColorCheck->setChecked(!MessageCore::MessageCoreSettings::self()->useDefaultColors());
397
    mUseInlineStyle->setChecked(MessageCore::MessageCoreSettings::self()->useRealHtmlMailColor());
Laurent Montel's avatar
Laurent Montel committed
398
    mRecycleColorCheck->setChecked(MessageViewer::MessageViewerSettings::self()->recycleQuoteColors());
Laurent Montel's avatar
Laurent Montel committed
399
    mCloseToQuotaThreshold->setValue(KMailSettings::self()->closeToQuotaThreshold());
Laurent Montel's avatar
Laurent Montel committed
400
    loadColor(true);
Laurent Montel's avatar
Laurent Montel committed
401
402
}

Laurent Montel's avatar
Laurent Montel committed
403
void AppearancePage::ColorsTab::loadColor(bool loadFromConfig)
Laurent Montel's avatar
Laurent Montel committed
404
{
405
    if (KMKernel::self()) {
Laurent Montel's avatar
Laurent Montel committed
406
        KConfigGroup reader(KMKernel::self()->config(), "Reader");
407
408

        static const QColor defaultColor[ numColorNames ] = {
Laurent Montel's avatar
Laurent Montel committed
409
410
411
            MessageCore::ColorUtil::self()->quoteLevel1DefaultTextColor(),
            MessageCore::ColorUtil::self()->quoteLevel2DefaultTextColor(),
            MessageCore::ColorUtil::self()->quoteLevel3DefaultTextColor(),
Laurent Montel's avatar
Laurent Montel committed
412
            MessageCore::ColorUtil::self()->linkColor(),   // link
413
414
415
416
417
418
            MessageList::Util::unreadDefaultMessageColor(), // unread mgs
            MessageList::Util::importantDefaultMessageColor(), // important msg
            MessageList::Util::todoDefaultMessageColor(), // action item mgs
            Qt::lightGray, // colorbar plain bg
            Qt::black,     // colorbar plain fg
            Qt::black,     // colorbar html  bg
Laurent Montel's avatar
Laurent Montel committed
419
            Qt::white     // colorbar html  fg
420
421
        };

Laurent Montel's avatar
Laurent Montel committed
422
        for (int i = 0; i < numColorNames; ++i) {
Laurent Montel's avatar
Laurent Montel committed
423
            if (loadFromConfig) {
424
                const QString configName = QLatin1String(colorNames[i].configName);
425
                if (configName == QLatin1String("UnreadMessageColor")) {
Laurent Montel's avatar
Laurent Montel committed
426
                    mColorList->setColorSilently(i, MessageList::MessageListSettings::self()->unreadMessageColor());
427
                } else if (configName == QLatin1String("ImportantMessageColor")) {
Laurent Montel's avatar
Laurent Montel committed
428
                    mColorList->setColorSilently(i, MessageList::MessageListSettings::self()->importantMessageColor());
429
                } else if (configName == QLatin1String("TodoMessageColor")) {
Laurent Montel's avatar
Laurent Montel committed
430
                    mColorList->setColorSilently(i, MessageList::MessageListSettings::self()->todoMessageColor());
431
                } else {
Laurent Montel's avatar
Laurent Montel committed
432
                    mColorList->setColorSilently(i, reader.readEntry(configName, defaultColor[i]));
433
                }
Laurent Montel's avatar
Laurent Montel committed
434
            } else {
Laurent Montel's avatar
Laurent Montel committed
435
                mColorList->setColorSilently(i, defaultColor[i]);
Laurent Montel's avatar
Laurent Montel committed
436
437
            }
        }
438
439
    } else {
        setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
440
441
442
443
444
    }
}

void AppearancePage::ColorsTab::doResetToDefaultsOther()
{
Laurent Montel's avatar
Laurent Montel committed
445
    mCustomColorCheck->setChecked(false);
446
    mUseInlineStyle->setChecked(false);
Laurent Montel's avatar
Laurent Montel committed
447
448
449
    mRecycleColorCheck->setChecked(false);
    mCloseToQuotaThreshold->setValue(80);
    loadColor(false);
Laurent Montel's avatar
Laurent Montel committed
450
451
452
453
}

void AppearancePage::ColorsTab::save()
{
Laurent Montel's avatar
Laurent Montel committed
454
    if (!KMKernel::self()) {
455
        return;
Laurent Montel's avatar
Laurent Montel committed
456
457
    }
    KConfigGroup reader(KMKernel::self()->config(), "Reader");
Laurent Montel's avatar
Laurent Montel committed
458
    bool customColors = mCustomColorCheck->isChecked();
Laurent Montel's avatar
Laurent Montel committed
459
    MessageCore::MessageCoreSettings::self()->setUseDefaultColors(!customColors);
460
    MessageCore::MessageCoreSettings::self()->setUseRealHtmlMailColor(mUseInlineStyle->isChecked());
Laurent Montel's avatar
Laurent Montel committed
461

Laurent Montel's avatar
Laurent Montel committed
462
    for (int i = 0; i < numColorNames; ++i) {
Laurent Montel's avatar
Laurent Montel committed
463
        const QString configName = QLatin1String(colorNames[i].configName);
464
        if (customColors && configName == QLatin1String("UnreadMessageColor")) {
Laurent Montel's avatar
Laurent Montel committed
465
            MessageList::MessageListSettings::self()->setUnreadMessageColor(mColorList->color(i));
466
        } else if (customColors && configName == QLatin1String("ImportantMessageColor")) {
Laurent Montel's avatar
Laurent Montel committed
467
            MessageList::MessageListSettings::self()->setImportantMessageColor(mColorList->color(i));
468
        } else if (customColors && configName == QLatin1String("TodoMessageColor")) {
Laurent Montel's avatar
Laurent Montel committed
469
            MessageList::MessageListSettings::self()->setTodoMessageColor(mColorList->color(i));
Laurent Montel's avatar
Laurent Montel committed
470
        } else {
Laurent Montel's avatar
Laurent Montel committed
471
472
473
            if (customColors || reader.hasKey(configName)) {
                reader.writeEntry(configName, mColorList->color(i));
            }
Laurent Montel's avatar
Laurent Montel committed
474
475
        }
    }
Laurent Montel's avatar
Laurent Montel committed
476
    MessageViewer::MessageViewerSettings::self()->setRecycleQuoteColors(mRecycleColorCheck->isChecked());
Laurent Montel's avatar
Laurent Montel committed
477
    KMailSettings::self()->setCloseToQuotaThreshold(mCloseToQuotaThreshold->value());
Laurent Montel's avatar
Laurent Montel committed
478
479
480
481
}

QString AppearancePage::LayoutTab::helpAnchor() const
{
Laurent Montel's avatar
Laurent Montel committed
482
    return QStringLiteral("configure-appearance-layout");
Laurent Montel's avatar
Laurent Montel committed
483
484
}

Laurent Montel's avatar
Laurent Montel committed
485
486
AppearancePageLayoutTab::AppearancePageLayoutTab(QWidget *parent)
    : ConfigModuleTab(parent)
Laurent Montel's avatar
Laurent Montel committed
487
{
Laurent Montel's avatar
Laurent Montel committed
488
    QVBoxLayout *vlay = new QVBoxLayout(this);
Laurent Montel's avatar
Laurent Montel committed
489
490

    // "folder list" radio buttons:
Laurent Montel's avatar
Laurent Montel committed
491
492
    populateButtonGroup(mFolderListGroupBox = new QGroupBox(this),
                        mFolderListGroup = new QButtonGroup(this),
Laurent Montel's avatar
Laurent Montel committed
493
                        Qt::Vertical, KMailSettings::self()->folderListItem());
Laurent Montel's avatar
Laurent Montel committed
494
    vlay->addWidget(mFolderListGroupBox);
Laurent Montel's avatar
Laurent Montel committed
495
    connect(mFolderListGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
496

Laurent Montel's avatar
Laurent Montel committed
497
498
    QHBoxLayout *folderCBHLayout = new QHBoxLayout;
    mFolderQuickSearchCB = new QCheckBox(i18n("Show folder quick search field"), this);
499
    connect(mFolderQuickSearchCB, &QAbstractButton::toggled, this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
500
501
    folderCBHLayout->addWidget(mFolderQuickSearchCB);
    vlay->addLayout(folderCBHLayout);
502

Laurent Montel's avatar
Laurent Montel committed
503
    // "favorite folders view mode" radio buttons:
Laurent Montel's avatar
Laurent Montel committed
504
505
506
507
    mFavoriteFoldersViewGroupBox = new QGroupBox(this);
    mFavoriteFoldersViewGroupBox->setTitle(i18n("Show Favorite Folders View"));
    mFavoriteFoldersViewGroupBox->setLayout(new QVBoxLayout());
    mFavoriteFoldersViewGroup = new QButtonGroup(this);
Laurent Montel's avatar
Laurent Montel committed
508
    connect(mFavoriteFoldersViewGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
509

Laurent Montel's avatar
Laurent Montel committed
510
511
512
    QRadioButton *favoriteFoldersViewHiddenRadio = new QRadioButton(i18n("Never"), mFavoriteFoldersViewGroupBox);
    mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewHiddenRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode));
    mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewHiddenRadio);
Laurent Montel's avatar
Laurent Montel committed
513

Laurent Montel's avatar
Laurent Montel committed
514
515
516
    QRadioButton *favoriteFoldersViewIconsRadio = new QRadioButton(i18n("As icons"), mFavoriteFoldersViewGroupBox);
    mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewIconsRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode));
    mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewIconsRadio);
Laurent Montel's avatar
Laurent Montel committed
517

Laurent Montel's avatar
Laurent Montel committed
518
    QRadioButton *favoriteFoldersViewListRadio = new QRadioButton(i18n("As list"), mFavoriteFoldersViewGroupBox);
Laurent Montel's avatar
Laurent Montel committed
519
    mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewListRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode));
Laurent Montel's avatar
Laurent Montel committed
520
    mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewListRadio);
Laurent Montel's avatar
Laurent Montel committed
521

Laurent Montel's avatar
Laurent Montel committed
522
    vlay->addWidget(mFavoriteFoldersViewGroupBox);
Laurent Montel's avatar
Laurent Montel committed
523
524

    // "folder tooltips" radio buttons:
Laurent Montel's avatar
Laurent Montel committed
525
526
527
528
    mFolderToolTipsGroupBox = new QGroupBox(this);
    mFolderToolTipsGroupBox->setTitle(i18n("Folder Tooltips"));
    mFolderToolTipsGroupBox->setLayout(new QVBoxLayout());
    mFolderToolTipsGroup = new QButtonGroup(this);
Laurent Montel's avatar
Laurent Montel committed
529
    connect(mFolderToolTipsGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged);
530

Laurent Montel's avatar
Laurent Montel committed
531
532
533
    QRadioButton *folderToolTipsAlwaysRadio = new QRadioButton(i18n("Always"), mFolderToolTipsGroupBox);
    mFolderToolTipsGroup->addButton(folderToolTipsAlwaysRadio, static_cast< int >(FolderTreeWidget::DisplayAlways));
    mFolderToolTipsGroupBox->layout()->addWidget(folderToolTipsAlwaysRadio);
Laurent Montel's avatar
Laurent Montel committed
534

Laurent Montel's avatar
Laurent Montel committed
535
536
537
    QRadioButton *folderToolTipsNeverRadio = new QRadioButton(i18n("Never"), mFolderToolTipsGroupBox);
    mFolderToolTipsGroup->addButton(folderToolTipsNeverRadio, static_cast< int >(FolderTreeWidget::DisplayNever));
    mFolderToolTipsGroupBox->layout()->addWidget(folderToolTipsNeverRadio);
Laurent Montel's avatar
Laurent Montel committed
538

Laurent Montel's avatar
Laurent Montel committed
539
    vlay->addWidget(mFolderToolTipsGroupBox);
Laurent Montel's avatar
Laurent Montel committed
540
541

    // "show reader window" radio buttons:
Laurent Montel's avatar
Laurent Montel committed
542
543
    populateButtonGroup(mReaderWindowModeGroupBox = new QGroupBox(this),
                        mReaderWindowModeGroup = new QButtonGroup(this),
Laurent Montel's avatar
Laurent Montel committed
544
                        Qt::Vertical, KMailSettings::self()->readerWindowModeItem());
Laurent Montel's avatar
Laurent Montel committed
545
    vlay->addWidget(mReaderWindowModeGroupBox);
546

Laurent Montel's avatar
Laurent Montel committed
547
    connect(mReaderWindowModeGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
548
549

    vlay->addStretch(10);   // spacer
Laurent Montel's avatar
Laurent Montel committed
550
551
552
553
}

void AppearancePage::LayoutTab::doLoadOther()
{
Laurent Montel's avatar
Laurent Montel committed
554
555
    loadWidget(mFolderListGroupBox, mFolderListGroup, KMailSettings::self()->folderListItem());
    loadWidget(mReaderWindowModeGroupBox, mReaderWindowModeGroup, KMailSettings::self()->readerWindowModeItem());
Laurent Montel's avatar
Laurent Montel committed
556
557
558
    if (KMKernel::self()) {
        loadWidget(mFavoriteFoldersViewGroupBox, mFavoriteFoldersViewGroup, KMKernel::self()->mailCommonSettings()->favoriteCollectionViewModeItem());
    }
559
    loadWidget(mFolderQuickSearchCB, KMailSettings::self()->enableFolderQuickSearchItem());
Laurent Montel's avatar
Laurent Montel committed
560
    const int checkedFolderToolTipsPolicy = KMailSettings::self()->toolTipDisplayPolicy();
Laurent Montel's avatar
Laurent Montel committed
561
562
563
    if (checkedFolderToolTipsPolicy >= 0) {
        mFolderToolTipsGroup->button(checkedFolderToolTipsPolicy)->setChecked(true);
    }
Laurent Montel's avatar
Laurent Montel committed
564
565
566
567
}

void AppearancePage::LayoutTab::save()
{
Laurent Montel's avatar
Laurent Montel committed
568
569
    saveButtonGroup(mFolderListGroup, KMailSettings::self()->folderListItem());
    saveButtonGroup(mReaderWindowModeGroup, KMailSettings::self()->readerWindowModeItem());
Laurent Montel's avatar
Laurent Montel committed
570
571
572
    if (KMKernel::self()) {
        saveButtonGroup(mFavoriteFoldersViewGroup, KMKernel::self()->mailCommonSettings()->favoriteCollectionViewModeItem());
    }
573
    saveCheckBox(mFolderQuickSearchCB, KMailSettings::self()->enableFolderQuickSearchItem());
Laurent Montel's avatar
Laurent Montel committed
574
    KMailSettings::self()->setToolTipDisplayPolicy(mFolderToolTipsGroup->checkedId());
Laurent Montel's avatar
Laurent Montel committed
575
576
577
578
579
580
581
582
}

//
// Appearance Message List
//

QString AppearancePage::HeadersTab::helpAnchor() const
{
Laurent Montel's avatar
Laurent Montel committed
583
    return QStringLiteral("configure-appearance-headers");
Laurent Montel's avatar
Laurent Montel committed
584
585
586
}

static const struct {
Laurent Montel's avatar
Laurent Montel committed
587
    const char *displayName;
Laurent Montel's avatar
Laurent Montel committed
588
589
590
591
592
593
594
    DateFormatter::FormatType dateDisplay;
} dateDisplayConfig[] = {
    { I18N_NOOP("Sta&ndard format (%1)"), KMime::DateFormatter::CTime },
    { I18N_NOOP("Locali&zed format (%1)"), KMime::DateFormatter::Localized },
    { I18N_NOOP("Smart for&mat (%1)"), KMime::DateFormatter::Fancy },
    { I18N_NOOP("C&ustom format:"), KMime::DateFormatter::Custom }
};
Laurent Montel's avatar
Laurent Montel committed
595
596
static const int numDateDisplayConfig
    = sizeof dateDisplayConfig / sizeof *dateDisplayConfig;
Laurent Montel's avatar
Laurent Montel committed
597

Laurent Montel's avatar
Laurent Montel committed
598
AppearancePageHeadersTab::AppearancePageHeadersTab(QWidget *parent)
Laurent Montel's avatar
Laurent Montel committed
599
600
    : ConfigModuleTab(parent)
    , mCustomDateFormatEdit(nullptr)
Laurent Montel's avatar
Laurent Montel committed
601
{
Laurent Montel's avatar
Laurent Montel committed
602
    QVBoxLayout *vlay = new QVBoxLayout(this);
Laurent Montel's avatar
Laurent Montel committed
603
604

    // "General Options" group:
Laurent Montel's avatar
Laurent Montel committed
605
606
    QGroupBox *group = new QGroupBox(i18nc("General options for the message list.", "General"), this);
    QVBoxLayout *gvlay = new QVBoxLayout(group);
Laurent Montel's avatar
Laurent Montel committed
607
608

    mDisplayMessageToolTips = new QCheckBox(
Laurent Montel's avatar
Laurent Montel committed
609
        MessageList::MessageListSettings::self()->messageToolTipEnabledItem()->label(), group);
Laurent Montel's avatar
Laurent Montel committed
610
    gvlay->addWidget(mDisplayMessageToolTips);
Laurent Montel's avatar
Laurent Montel committed
611

612
613
    connect(mDisplayMessageToolTips, &QCheckBox::stateChanged,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
614
615
616

    // "Aggregation"
    using MessageList::Utils::AggregationComboBox;
Laurent Montel's avatar
Laurent Montel committed
617
    mAggregationComboBox = new AggregationComboBox(group);
Laurent Montel's avatar
Laurent Montel committed
618

Laurent Montel's avatar
Laurent Montel committed
619
620
    QLabel *aggregationLabel = new QLabel(i18n("Default aggregation:"), group);
    aggregationLabel->setBuddy(mAggregationComboBox);
Laurent Montel's avatar
Laurent Montel committed
621
622

    using MessageList::Utils::AggregationConfigButton;
Laurent Montel's avatar
Laurent Montel committed
623
    AggregationConfigButton *aggregationConfigButton = new AggregationConfigButton(group, mAggregationComboBox);
Laurent Montel's avatar
Laurent Montel committed
624

Laurent Montel's avatar
Laurent Montel committed
625
626
627
628
629
    QHBoxLayout *aggregationLayout = new QHBoxLayout();
    aggregationLayout->addWidget(aggregationLabel, 1);
    aggregationLayout->addWidget(mAggregationComboBox, 1);
    aggregationLayout->addWidget(aggregationConfigButton, 0);
    gvlay->addLayout(aggregationLayout);
Laurent Montel's avatar
Laurent Montel committed
630

631
632
    connect(aggregationConfigButton, &MessageList::Utils::AggregationConfigButton::configureDialogCompleted,
            this, &AppearancePageHeadersTab::slotSelectDefaultAggregation);
Laurent Montel's avatar
Laurent Montel committed
633
    connect(mAggregationComboBox, qOverload<int>(&MessageList::Utils::AggregationComboBox::activated),
634
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
635
636
637

    // "Theme"
    using MessageList::Utils::ThemeComboBox;
Laurent Montel's avatar
Laurent Montel committed
638
    mThemeComboBox = new ThemeComboBox(group);
Laurent Montel's avatar
Laurent Montel committed
639

Laurent Montel's avatar
Laurent Montel committed
640
641
    QLabel *themeLabel = new QLabel(i18n("Default theme:"), group);
    themeLabel->setBuddy(mThemeComboBox);
Laurent Montel's avatar
Laurent Montel committed
642
643

    using MessageList::Utils::ThemeConfigButton;
Laurent Montel's avatar
Laurent Montel committed
644
    ThemeConfigButton *themeConfigButton = new ThemeConfigButton(group, mThemeComboBox);
Laurent Montel's avatar
Laurent Montel committed
645

Laurent Montel's avatar
Laurent Montel committed
646
647
648
649
650
    QHBoxLayout *themeLayout = new QHBoxLayout();
    themeLayout->addWidget(themeLabel, 1);
    themeLayout->addWidget(mThemeComboBox, 1);
    themeLayout->addWidget(themeConfigButton, 0);
    gvlay->addLayout(themeLayout);
Laurent Montel's avatar
Laurent Montel committed
651

652
653
    connect(themeConfigButton, &MessageList::Utils::ThemeConfigButton::configureDialogCompleted,
            this, &AppearancePageHeadersTab::slotSelectDefaultTheme);
Laurent Montel's avatar
Laurent Montel committed
654
    connect(mThemeComboBox, qOverload<int>(&MessageList::Utils::ThemeComboBox::activated),
655
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
656

Laurent Montel's avatar
Laurent Montel committed
657
    vlay->addWidget(group);
Laurent Montel's avatar
Laurent Montel committed
658
659

    // "Date Display" group:
Volker Krause's avatar
Volker Krause committed
660
661
662
663
664
    mDateDisplayBox = new QGroupBox(this);
    mDateDisplayBox->setTitle(i18n("Date Display"));
    mDateDisplay = new QButtonGroup(this);
    mDateDisplay->setExclusive(true);
    gvlay = new QVBoxLayout(mDateDisplayBox);
Laurent Montel's avatar
Laurent Montel committed
665

Laurent Montel's avatar
Laurent Montel committed
666
    for (int i = 0; i < numDateDisplayConfig; ++i) {
Laurent Montel's avatar
Laurent Montel committed
667
668
        const char *label = dateDisplayConfig[i].displayName;
        QString buttonLabel;
Laurent Montel's avatar
Laurent Montel committed
669
        if (QString::fromLatin1(label).contains(QLatin1String("%1"))) {
Laurent Montel's avatar
Laurent Montel committed
670
671
672
673
674
            buttonLabel = i18n(label, DateFormatter::formatCurrentDate(dateDisplayConfig[i].dateDisplay));
        } else {
            buttonLabel = i18n(label);
        }
        if (dateDisplayConfig[i].dateDisplay == DateFormatter::Custom) {
Volker Krause's avatar
Volker Krause committed
675
            QWidget *hbox = new QWidget(mDateDisplayBox);
Laurent Montel's avatar
Laurent Montel committed
676
            QHBoxLayout *hboxHBoxLayout = new QHBoxLayout(hbox);
677
            hboxHBoxLayout->setContentsMargins(0, 0, 0, 0);
Laurent Montel's avatar
Laurent Montel committed
678
679
680
            QRadioButton *radio = new QRadioButton(buttonLabel, hbox);
            hboxHBoxLayout->addWidget(radio);
            mDateDisplay->addButton(radio, dateDisplayConfig[i].dateDisplay);
Laurent Montel's avatar
Laurent Montel committed
681

Laurent Montel's avatar
Laurent Montel committed
682
683
            mCustomDateFormatEdit = new QLineEdit(hbox);
            new KPIM::LineEditCatchReturnKey(mCustomDateFormatEdit, this);
Laurent Montel's avatar
Laurent Montel committed
684
            hboxHBoxLayout->addWidget(mCustomDateFormatEdit);
Laurent Montel's avatar
Laurent Montel committed
685
686
            mCustomDateFormatEdit->setEnabled(false);
            hboxHBoxLayout->setStretchFactor(mCustomDateFormatEdit, 1);
Laurent Montel's avatar
Laurent Montel committed
687

688
689
690
691
            connect(radio, &QAbstractButton::toggled,
                    mCustomDateFormatEdit, &QWidget::setEnabled);
            connect(mCustomDateFormatEdit, &QLineEdit::textChanged,
                    this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
692
693

            QLabel *formatHelp = new QLabel(
Laurent Montel's avatar
Laurent Montel committed
694
                i18n("<qt><a href=\"whatsthis1\">Custom format information...</a></qt>"), hbox);
695
            formatHelp->setContextMenuPolicy(Qt::NoContextMenu);
696
697
            connect(formatHelp, &QLabel::linkActivated,
                    this, &AppearancePageHeadersTab::slotLinkClicked);
Laurent Montel's avatar
Laurent Montel committed
698
            hboxHBoxLayout->addWidget(formatHelp);
Laurent Montel's avatar
Laurent Montel committed
699

Laurent Montel's avatar
Laurent Montel committed
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
            mCustomDateWhatsThis
                = i18n("<qt><p><strong>These expressions may be used for the date:"
                       "</strong></p>"
                       "<ul>"
                       "<li>d - the day as a number without a leading zero (1-31)</li>"
                       "<li>dd - the day as a number with a leading zero (01-31)</li>"
                       "<li>ddd - the abbreviated day name (Mon - Sun)</li>"
                       "<li>dddd - the long day name (Monday - Sunday)</li>"
                       "<li>M - the month as a number without a leading zero (1-12)</li>"
                       "<li>MM - the month as a number with a leading zero (01-12)</li>"
                       "<li>MMM - the abbreviated month name (Jan - Dec)</li>"
                       "<li>MMMM - the long month name (January - December)</li>"
                       "<li>yy - the year as a two digit number (00-99)</li>"
                       "<li>yyyy - the year as a four digit number (0000-9999)</li>"
                       "</ul>"
                       "<p><strong>These expressions may be used for the time:"
                       "</strong></p> "
                       "<ul>"
                       "<li>h - the hour without a leading zero (0-23 or 1-12 if AM/PM display)</li>"
                       "<li>hh - the hour with a leading zero (00-23 or 01-12 if AM/PM display)</li>"
                       "<li>m - the minutes without a leading zero (0-59)</li>"
                       "<li>mm - the minutes with a leading zero (00-59)</li>"
                       "<li>s - the seconds without a leading zero (0-59)</li>"
                       "<li>ss - the seconds with a leading zero (00-59)</li>"
                       "<li>z - the milliseconds without leading zeroes (0-999)</li>"
                       "<li>zzz - the milliseconds with leading zeroes (000-999)</li>"
                       "<li>AP - switch to AM/PM display. AP will be replaced by either \"AM\" or \"PM\".</li>"
                       "<li>ap - switch to AM/PM display. ap will be replaced by either \"am\" or \"pm\".</li>"
                       "<li>Z - time zone in numeric form (-0500)</li>"
                       "</ul>"
                       "<p><strong>All other input characters will be ignored."
                       "</strong></p></qt>");
Laurent Montel's avatar
Laurent Montel committed
732
733
734
            mCustomDateFormatEdit->setWhatsThis(mCustomDateWhatsThis);
            radio->setWhatsThis(mCustomDateWhatsThis);
            gvlay->addWidget(hbox);
Laurent Montel's avatar
Laurent Montel committed
735
736
737
738
        } else {
            QRadioButton *radio = new QRadioButton(buttonLabel, mDateDisplayBox);
            gvlay->addWidget(radio);
            mDateDisplay->addButton(radio, dateDisplayConfig[i].dateDisplay);
Laurent Montel's avatar
Laurent Montel committed
739
740
741
        }
    } // end for loop populating mDateDisplay

Volker Krause's avatar
Volker Krause committed
742
    vlay->addWidget(mDateDisplayBox);
Laurent Montel's avatar
Laurent Montel committed
743
    connect(mDateDisplay, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
744
745

    vlay->addStretch(10);   // spacer
Laurent Montel's avatar
Laurent Montel committed
746
747
}

Laurent Montel's avatar
Laurent Montel committed
748
void AppearancePageHeadersTab::slotLinkClicked(const QString &link)
Laurent Montel's avatar
Laurent Montel committed
749
{
Laurent Montel's avatar
Laurent Montel committed
750
751
752
    if (link == QLatin1String("whatsthis1")) {
        QWhatsThis::showText(QCursor::pos(), mCustomDateWhatsThis);
    }
Laurent Montel's avatar
Laurent Montel committed
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
}

void AppearancePage::HeadersTab::slotSelectDefaultAggregation()
{
    // Select current default aggregation.
    mAggregationComboBox->selectDefault();
}

void AppearancePage::HeadersTab::slotSelectDefaultTheme()
{
    // Select current default theme.
    mThemeComboBox->selectDefault();
}

void AppearancePage::HeadersTab::doLoadOther()
{
    // "General Options":
Laurent Montel's avatar
Laurent Montel committed
770
    loadWidget(mDisplayMessageToolTips, MessageList::MessageListSettings::self()->messageToolTipEnabledItem());
Laurent Montel's avatar
Laurent Montel committed
771
772
773
774
775
776
777
778

    // "Aggregation":
    slotSelectDefaultAggregation();

    // "Theme":
    slotSelectDefaultTheme();

    // "Date Display":
Laurent Montel's avatar
Laurent Montel committed
779
780
    setDateDisplay(MessageCore::MessageCoreSettings::self()->dateFormat(),
                   MessageCore::MessageCoreSettings::self()->customDateFormat());
Laurent Montel's avatar
Laurent Montel committed
781
782
783
784
}

void AppearancePage::HeadersTab::doLoadFromGlobalSettings()
{
Laurent Montel's avatar
Laurent Montel committed
785
    loadWidget(mDisplayMessageToolTips, MessageList::MessageListSettings::self()->messageToolTipEnabledItem());
Laurent Montel's avatar
Laurent Montel committed
786
787
788
789
790
791
    // "Aggregation":
    slotSelectDefaultAggregation();

    // "Theme":
    slotSelectDefaultTheme();

Laurent Montel's avatar
Laurent Montel committed
792
793
    setDateDisplay(MessageCore::MessageCoreSettings::self()->dateFormat(),
                   MessageCore::MessageCoreSettings::self()->customDateFormat());
Laurent Montel's avatar
Laurent Montel committed
794
795
}

Laurent Montel's avatar
Laurent Montel committed
796
void AppearancePage::HeadersTab::setDateDisplay(int num, const QString &format)
Laurent Montel's avatar
Laurent Montel committed
797
{
Laurent Montel's avatar
Laurent Montel committed
798
799
    DateFormatter::FormatType dateDisplay
        = static_cast<DateFormatter::FormatType>(num);
Laurent Montel's avatar
Laurent Montel committed
800
801

    // special case: needs text for the line edit:
Laurent Montel's avatar
Laurent Montel committed
802
803
804
    if (dateDisplay == DateFormatter::Custom) {
        mCustomDateFormatEdit->setText(format);
    }
Laurent Montel's avatar
Laurent Montel committed
805

Laurent Montel's avatar
Laurent Montel committed
806
    for (int i = 0; i < numDateDisplayConfig; ++i) {
Laurent Montel's avatar
Laurent Montel committed
807
        if (dateDisplay == dateDisplayConfig[i].dateDisplay) {
Volker Krause's avatar
Volker Krause committed
808
            mDateDisplay->button(dateDisplay)->setChecked(true);
Laurent Montel's avatar
Laurent Montel committed
809
810
            return;
        }
Laurent Montel's avatar
Laurent Montel committed
811
    }
Laurent Montel's avatar
Laurent Montel committed
812
    // fell through since none found:
Volker Krause's avatar
Volker Krause committed
813
    mDateDisplay->button(numDateDisplayConfig - 2)->setChecked(true);   // default
Laurent Montel's avatar
Laurent Montel committed
814
815
816
817
}

void AppearancePage::HeadersTab::save()
{
Laurent Montel's avatar
Laurent Montel committed
818
    saveCheckBox(mDisplayMessageToolTips, MessageList::MessageListSettings::self()->messageToolTipEnabledItem());
Laurent Montel's avatar
Laurent Montel committed
819

Laurent Montel's avatar
Laurent Montel committed
820
821
822
    if (KMKernel::self()) {
        KMKernel::self()->savePaneSelection();
    }
Laurent Montel's avatar
Laurent Montel committed
823
824
825
826
827
828
    // "Aggregation"
    mAggregationComboBox->writeDefaultConfig();

    // "Theme"
    mThemeComboBox->writeDefaultConfig();

Volker Krause's avatar
Volker Krause committed
829
    const int dateDisplayID = mDateDisplay->checkedId();
Laurent Montel's avatar
Laurent Montel committed
830
831
    MessageCore::MessageCoreSettings::self()->setDateFormat(dateDisplayID);
    MessageCore::MessageCoreSettings::self()->setCustomDateFormat(mCustomDateFormatEdit->text());
Laurent Montel's avatar
Laurent Montel committed
832
833
834
835
836
837
838
839
}

//
// Message Window
//

QString AppearancePage::ReaderTab::helpAnchor() const
{
Laurent Montel's avatar
Laurent Montel committed
840
    return QStringLiteral("configure-appearance-reader");
Laurent Montel's avatar
Laurent Montel committed
841
842
}

Laurent Montel's avatar
Laurent Montel committed
843
AppearancePageGeneralTab::AppearancePageGeneralTab(QWidget *parent)
Laurent Montel's avatar
Laurent Montel committed
844
    : ConfigModuleTab(parent)
Laurent Montel's avatar
Laurent Montel committed
845
846
847
{
    QVBoxLayout *topLayout = new QVBoxLayout(this);

Laurent Montel's avatar
Laurent Montel committed
848
849
850
851
852
    QGroupBox *readerBox = new QGroupBox(i18n("Message Window"), this);
    topLayout->addWidget(readerBox);

    QVBoxLayout *readerBoxLayout = new QVBoxLayout(readerBox);

Laurent Montel's avatar
Laurent Montel committed
853
    // "Close message window after replying or forwarding" check box:
Laurent Montel's avatar
Laurent Montel committed
854
    populateCheckBox(mCloseAfterReplyOrForwardCheck = new QCheckBox(this),
855
                     MessageViewer::MessageViewerSettings::self()->closeAfterReplyOrForwardItem());
Laurent Montel's avatar
Laurent Montel committed
856
    mCloseAfterReplyOrForwardCheck->setToolTip(
Laurent Montel's avatar
Laurent Montel committed
857
        i18n("Close the standalone message window after replying or forwarding the message"));
Laurent Montel's avatar
Laurent Montel committed
858
    readerBoxLayout->addWidget(mCloseAfterReplyOrForwardCheck);
859
860
    connect(mCloseAfterReplyOrForwardCheck, &QCheckBox::stateChanged,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
861
862

    mViewerSettings = new MessageViewer::ConfigureWidget;
863
864
    connect(mViewerSettings, &MessageViewer::ConfigureWidget::settingsChanged,
            this, &ConfigModuleTab::slotEmitChanged);
Laurent Montel's avatar
Laurent Montel committed
865
    readerBoxLayout->addWidget(mViewerSettings);
Laurent Montel's avatar
Laurent Montel committed
866

Laurent Montel's avatar
Laurent Montel committed
867
868
869
870
871
872
873
874
    QGroupBox *systrayBox = new QGroupBox(i18n("System Tray"), this);
    topLayout->addWidget(systrayBox);

    QVBoxLayout *systrayBoxlayout = new QVBoxLayout(systrayBox);

    // "Enable system tray applet" check box
    mSystemTrayCheck = new QCheckBox(i18n("Enable system tray icon"), this);
    systrayBoxlayout->addWidget(mSystemTrayCheck);
875
876
877
878
879
880
881

    // "Enable start in system tray" check box
    mStartInTrayCheck = new QCheckBox(i18n("Start minimized to tray"));
    systrayBoxlayout->addWidget(mStartInTrayCheck);

    // Dependencies between the two checkboxes
    connect(mStartInTrayCheck, &QCheckBox::stateChanged, this, [this](int state) {
Laurent Montel's avatar
Laurent Montel committed
882
883
884
885
        if (state == Qt::Checked) {
            mSystemTrayCheck->setCheckState(Qt::Checked);
        }
        slotEmitChanged();
886
887
    });
    connect(mSystemTrayCheck, &QCheckBox::stateChanged, this, [this](int state) {
Laurent Montel's avatar
Laurent Montel committed
888
889
890
891
        if (state == Qt::Unchecked) {
            mStartInTrayCheck->setCheckState(Qt::Unchecked);
        }
        slotEmitChanged();
892
    });
Laurent Montel's avatar
Laurent Montel committed
893

894
895
896
897
898
899
    // "Enable system tray applet" check box
    mShowNumberInTaskBar = new QCheckBox(i18n("Show unread email in Taskbar"), this);
    systrayBoxlayout->addWidget(mShowNumberInTaskBar);
    connect(mShowNumberInTaskBar, &QCheckBox::stateChanged,
            this, &ConfigModuleTab::slotEmitChanged);

Laurent Montel's avatar
Laurent Montel committed
900
    topLayout->addStretch(100);   // spacer
Laurent Montel's avatar
Laurent Montel committed
901
902
903
904
905
906
907
908
}

void AppearancePage::ReaderTab::doResetToDefaultsOther()
{
}

void AppearancePage::ReaderTab::doLoadOther()
{
Laurent Montel's avatar
Laurent Montel committed
909
    loadWidget(mSystemTrayCheck, KMailSettings::self()->systemTrayEnabledItem());
910
    loadWidget(mStartInTrayCheck,</