You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1379 lines
54 KiB
1379 lines
54 KiB
/* |
|
SPDX-FileCopyrightText: 2013-2020 Laurent Montel <montel@kde.org> |
|
|
|
SPDX-License-Identifier: GPL-2.0-only |
|
*/ |
|
|
|
#include "configureappearancepage.h" |
|
#include <PimCommon/ConfigureImmutableWidgetUtils> |
|
using namespace PimCommon::ConfigureImmutableWidgetUtils; |
|
#include "configuredialog/colorlistbox.h" |
|
#include <MessageList/AggregationComboBox> |
|
#include <MessageList/AggregationConfigButton> |
|
#include <MessageList/ThemeComboBox> |
|
#include <MessageList/ThemeConfigButton> |
|
#include <Libkdepim/LineEditCatchReturnKey> |
|
#include "messagelistsettings.h" |
|
#include <MailCommon/TagWidget> |
|
#include "kmkernel.h" |
|
|
|
#include "util.h" |
|
#include <MailCommon/FolderTreeWidget> |
|
|
|
#include "kmmainwidget.h" |
|
|
|
#include "mailcommonsettings_base.h" |
|
|
|
#include <MessageViewer/ConfigureWidget> |
|
#include <MessageViewer/MessageViewerSettings> |
|
|
|
#include <MessageList/MessageListUtil> |
|
#include <MessageCore/MessageCoreSettings> |
|
#include <MessageCore/MessageCoreUtil> |
|
#include "settings/kmailsettings.h" |
|
|
|
#include <MailCommon/MailUtil> |
|
|
|
#include <AkonadiCore/Tag> |
|
#include <AkonadiCore/TagFetchJob> |
|
#include <AkonadiCore/TagFetchScope> |
|
#include <AkonadiCore/TagDeleteJob> |
|
#include <AkonadiCore/TagCreateJob> |
|
#include <AkonadiCore/TagAttribute> |
|
#include <AkonadiCore/TagModifyJob> |
|
|
|
#include <KIconButton> |
|
#include <KLocalizedString> |
|
#include <KColorScheme> |
|
#include <KSeparator> |
|
#include <KFontChooser> |
|
#include <QHBoxLayout> |
|
#include <KMessageBox> |
|
#include <KKeySequenceWidget> |
|
#include <QLineEdit> |
|
#include <QIcon> |
|
#include "kmail_debug.h" |
|
|
|
#include <kmime/kmime_dateformatter.h> |
|
using KMime::DateFormatter; |
|
|
|
#include <QWhatsThis> |
|
#include <QButtonGroup> |
|
#include <QSpinBox> |
|
#include <QLabel> |
|
#include <QFontDatabase> |
|
#include <QGroupBox> |
|
#include <QVBoxLayout> |
|
#include <QRadioButton> |
|
#include <QCheckBox> |
|
using namespace MailCommon; |
|
|
|
QString AppearancePage::helpAnchor() const |
|
{ |
|
return QStringLiteral("configure-appearance"); |
|
} |
|
|
|
AppearancePage::AppearancePage(QWidget *parent) |
|
: ConfigModuleWithTabs(parent) |
|
{ |
|
// |
|
// "General" tab: |
|
// |
|
auto *readerTab = new ReaderTab(); |
|
addTab(readerTab, i18n("General")); |
|
addConfig(MessageViewer::MessageViewerSettings::self(), readerTab); |
|
|
|
// |
|
// "Fonts" tab: |
|
// |
|
auto *fontsTab = new FontsTab(); |
|
addTab(fontsTab, i18n("Fonts")); |
|
|
|
// |
|
// "Colors" tab: |
|
// |
|
auto *colorsTab = new ColorsTab(); |
|
addTab(colorsTab, i18n("Colors")); |
|
|
|
// |
|
// "Layout" tab: |
|
// |
|
auto *layoutTab = new LayoutTab(); |
|
addTab(layoutTab, i18n("Layout")); |
|
|
|
// |
|
// "Headers" tab: |
|
// |
|
auto *headersTab = new HeadersTab(); |
|
addTab(headersTab, i18n("Message List")); |
|
|
|
// |
|
// "Message Tag" tab: |
|
// |
|
auto *messageTagTab = new MessageTagTab(); |
|
addTab(messageTagTab, i18n("Message Tags")); |
|
} |
|
|
|
QString AppearancePage::FontsTab::helpAnchor() const |
|
{ |
|
return QStringLiteral("configure-appearance-fonts"); |
|
} |
|
|
|
static const struct { |
|
const char *configName; |
|
const char *displayName; |
|
bool enableFamilyAndSize; |
|
bool onlyFixed; |
|
} fontNames[] = { |
|
{ "body-font", I18N_NOOP("Message Body"), true, false }, |
|
{ "MessageListFont", I18N_NOOP("Message List"), true, false }, |
|
{ "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 }, |
|
{ "fixed-font", I18N_NOOP("Fixed Width Font"), true, true }, |
|
{ "composer-font", I18N_NOOP("Composer"), true, false }, |
|
{ "print-font", I18N_NOOP("Printing Output"), true, false }, |
|
}; |
|
static const int numFontNames = sizeof fontNames / sizeof *fontNames; |
|
|
|
AppearancePageFontsTab::AppearancePageFontsTab(QWidget *parent) |
|
: ConfigModuleTab(parent) |
|
{ |
|
assert(numFontNames == sizeof mFont / sizeof *mFont); |
|
|
|
// "Use custom fonts" checkbox, followed by <hr> |
|
auto *vlay = new QVBoxLayout(this); |
|
mCustomFontCheck = new QCheckBox(i18n("&Use custom fonts"), this); |
|
vlay->addWidget(mCustomFontCheck); |
|
vlay->addWidget(new KSeparator(Qt::Horizontal, this)); |
|
connect(mCustomFontCheck, &QCheckBox::stateChanged, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
// "font location" combo box and label: |
|
auto *hlay = new QHBoxLayout(); // inherites spacing |
|
vlay->addLayout(hlay); |
|
mFontLocationCombo = new QComboBox(this); |
|
mFontLocationCombo->setEnabled(false); // !mCustomFontCheck->isChecked() |
|
|
|
QStringList fontDescriptions; |
|
fontDescriptions.reserve(numFontNames); |
|
for (int i = 0; i < numFontNames; ++i) { |
|
fontDescriptions << i18n(fontNames[i].displayName); |
|
} |
|
mFontLocationCombo->addItems(fontDescriptions); |
|
|
|
QLabel *label = new QLabel(i18n("Apply &to:"), this); |
|
label->setBuddy(mFontLocationCombo); |
|
label->setEnabled(false); // since !mCustomFontCheck->isChecked() |
|
hlay->addWidget(label); |
|
|
|
hlay->addWidget(mFontLocationCombo); |
|
hlay->addStretch(10); |
|
mFontChooser = new KFontChooser(this, KFontChooser::DisplayFrame, |
|
QStringList(), 4); |
|
mFontChooser->setEnabled(false); // since !mCustomFontCheck->isChecked() |
|
vlay->addWidget(mFontChooser); |
|
connect(mFontChooser, &KFontChooser::fontSelected, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
// {en,dis}able widgets depending on the state of mCustomFontCheck: |
|
connect(mCustomFontCheck, &QAbstractButton::toggled, |
|
label, &QWidget::setEnabled); |
|
connect(mCustomFontCheck, &QAbstractButton::toggled, |
|
mFontLocationCombo, &QWidget::setEnabled); |
|
connect(mCustomFontCheck, &QAbstractButton::toggled, |
|
mFontChooser, &QWidget::setEnabled); |
|
// load the right font settings into mFontChooser: |
|
connect(mFontLocationCombo, qOverload<int>(&QComboBox::activated), |
|
this, &AppearancePage::FontsTab::slotFontSelectorChanged); |
|
} |
|
|
|
void AppearancePage::FontsTab::slotFontSelectorChanged(int index) |
|
{ |
|
qCDebug(KMAIL_LOG) << "slotFontSelectorChanged() called"; |
|
if (index < 0 || index >= mFontLocationCombo->count()) { |
|
return; // Should never happen, but it is better to check. |
|
} |
|
|
|
// Save current fontselector setting before we install the new: |
|
if (mActiveFontIndex == 0) { |
|
mFont[0] = mFontChooser->font(); |
|
// hardcode the family and size of "message body" dependent fonts: |
|
for (int i = 0; i < numFontNames; ++i) { |
|
if (!fontNames[i].enableFamilyAndSize) { |
|
// ### 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? |
|
mFont[i].setFamily(mFont[0].family()); |
|
mFont[i].setPointSize/*Float?*/ (mFont[0].pointSize/*Float?*/ ()); |
|
} |
|
} |
|
} else if (mActiveFontIndex > 0) { |
|
mFont[ mActiveFontIndex ] = mFontChooser->font(); |
|
} |
|
mActiveFontIndex = index; |
|
|
|
// Disonnect so the "Apply" button is not activated by the change |
|
disconnect(mFontChooser, &KFontChooser::fontSelected, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
// Display the new setting: |
|
mFontChooser->setFont(mFont[index], fontNames[index].onlyFixed); |
|
|
|
connect(mFontChooser, &KFontChooser::fontSelected, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
// Disable Family and Size list if we have selected a quote font: |
|
mFontChooser->enableColumn(KFontChooser::FamilyList | KFontChooser::SizeList, |
|
fontNames[ index ].enableFamilyAndSize); |
|
} |
|
|
|
void AppearancePage::FontsTab::doLoadOther() |
|
{ |
|
if (KMKernel::self()) { |
|
KConfigGroup fonts(KMKernel::self()->config(), "Fonts"); |
|
|
|
mFont[0] = QFontDatabase::systemFont(QFontDatabase::GeneralFont); |
|
QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); |
|
|
|
for (int i = 0; i < numFontNames; ++i) { |
|
const QString configName = QLatin1String(fontNames[i].configName); |
|
if (configName == QLatin1String("MessageListFont")) { |
|
mFont[i] = MessageList::MessageListSettings::self()->messageListFont(); |
|
} else if (configName == QLatin1String("UnreadMessageFont")) { |
|
mFont[i] = MessageList::MessageListSettings::self()->unreadMessageFont(); |
|
} else if (configName == QLatin1String("ImportantMessageFont")) { |
|
mFont[i] = MessageList::MessageListSettings::self()->importantMessageFont(); |
|
} else if (configName == QLatin1String("TodoMessageFont")) { |
|
mFont[i] = MessageList::MessageListSettings::self()->todoMessageFont(); |
|
} else { |
|
mFont[i] = fonts.readEntry(configName, |
|
(fontNames[i].onlyFixed) ? fixedFont : mFont[0]); |
|
} |
|
} |
|
mCustomFontCheck->setChecked(!MessageCore::MessageCoreSettings::self()->useDefaultFonts()); |
|
mFontLocationCombo->setCurrentIndex(0); |
|
slotFontSelectorChanged(0); |
|
} else { |
|
setEnabled(false); |
|
} |
|
} |
|
|
|
void AppearancePage::FontsTab::save() |
|
{ |
|
if (KMKernel::self()) { |
|
KConfigGroup fonts(KMKernel::self()->config(), "Fonts"); |
|
|
|
// read the current font (might have been modified) |
|
if (mActiveFontIndex >= 0) { |
|
mFont[ mActiveFontIndex ] = mFontChooser->font(); |
|
} |
|
|
|
const bool customFonts = mCustomFontCheck->isChecked(); |
|
MessageCore::MessageCoreSettings::self()->setUseDefaultFonts(!customFonts); |
|
|
|
for (int i = 0; i < numFontNames; ++i) { |
|
const QString configName = QLatin1String(fontNames[i].configName); |
|
if (customFonts && configName == QLatin1String("MessageListFont")) { |
|
MessageList::MessageListSettings::self()->setMessageListFont(mFont[i]); |
|
} else if (customFonts && configName == QLatin1String("UnreadMessageFont")) { |
|
MessageList::MessageListSettings::self()->setUnreadMessageFont(mFont[i]); |
|
} else if (customFonts && configName == QLatin1String("ImportantMessageFont")) { |
|
MessageList::MessageListSettings::self()->setImportantMessageFont(mFont[i]); |
|
} else if (customFonts && configName == QLatin1String("TodoMessageFont")) { |
|
MessageList::MessageListSettings::self()->setTodoMessageFont(mFont[i]); |
|
} else { |
|
if (customFonts || fonts.hasKey(configName)) { |
|
// Don't write font info when we use default fonts, but write |
|
// if it's already there: |
|
fonts.writeEntry(configName, mFont[i]); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void AppearancePage::FontsTab::doResetToDefaultsOther() |
|
{ |
|
mCustomFontCheck->setChecked(false); |
|
} |
|
|
|
QString AppearancePage::ColorsTab::helpAnchor() const |
|
{ |
|
return QStringLiteral("configure-appearance-colors"); |
|
} |
|
|
|
static const struct { |
|
const char *configName; |
|
const char *displayName; |
|
} colorNames[] = { // adjust doLoadOther if you change this: |
|
{ "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") }, |
|
{ "ColorbarBackgroundHTML", I18N_NOOP("HTML Status Bar Background - HTML Message") }, |
|
{ "ColorbarForegroundHTML", I18N_NOOP("HTML Status Bar Foreground - HTML Message") } |
|
}; |
|
static const int numColorNames = sizeof colorNames / sizeof *colorNames; |
|
|
|
AppearancePageColorsTab::AppearancePageColorsTab(QWidget *parent) |
|
: ConfigModuleTab(parent) |
|
{ |
|
// "use custom colors" check box |
|
auto *vlay = new QVBoxLayout(this); |
|
mCustomColorCheck = new QCheckBox(i18n("&Use custom colors"), this); |
|
vlay->addWidget(mCustomColorCheck); |
|
connect(mCustomColorCheck, &QCheckBox::stateChanged, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
mUseInlineStyle = new QCheckBox(i18n("&Do not change color from original HTML mail"), this); |
|
vlay->addWidget(mUseInlineStyle); |
|
connect(mUseInlineStyle, &QCheckBox::stateChanged, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
// color list box: |
|
mColorList = new ColorListBox(this); |
|
mColorList->setEnabled(false); // since !mCustomColorCheck->isChecked() |
|
for (int i = 0; i < numColorNames; ++i) { |
|
mColorList->addColor(i18n(colorNames[i].displayName)); |
|
} |
|
vlay->addWidget(mColorList, 1); |
|
|
|
// "recycle colors" check box: |
|
mRecycleColorCheck |
|
= new QCheckBox(i18n("Recycle colors on deep "ing"), this); |
|
mRecycleColorCheck->setEnabled(false); |
|
vlay->addWidget(mRecycleColorCheck); |
|
connect(mRecycleColorCheck, &QCheckBox::stateChanged, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
// close to quota threshold |
|
auto *hbox = new QHBoxLayout(); |
|
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); |
|
connect(mCloseToQuotaThreshold, qOverload<int>(&QSpinBox::valueChanged), |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
mCloseToQuotaThreshold->setSuffix(i18n("%")); |
|
|
|
hbox->addWidget(mCloseToQuotaThreshold); |
|
hbox->addWidget(new QWidget(this), 2); |
|
|
|
// {en,dir}able widgets depending on the state of mCustomColorCheck: |
|
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); |
|
} |
|
|
|
void AppearancePage::ColorsTab::doLoadOther() |
|
{ |
|
mCustomColorCheck->setChecked(!MessageCore::MessageCoreSettings::self()->useDefaultColors()); |
|
mUseInlineStyle->setChecked(MessageCore::MessageCoreSettings::self()->useRealHtmlMailColor()); |
|
mRecycleColorCheck->setChecked(MessageViewer::MessageViewerSettings::self()->recycleQuoteColors()); |
|
mCloseToQuotaThreshold->setValue(KMailSettings::self()->closeToQuotaThreshold()); |
|
loadColor(true); |
|
} |
|
|
|
void AppearancePage::ColorsTab::loadColor(bool loadFromConfig) |
|
{ |
|
if (KMKernel::self()) { |
|
KConfigGroup reader(KMKernel::self()->config(), "Reader"); |
|
|
|
static const QColor defaultColor[ numColorNames ] = { |
|
MessageCore::ColorUtil::self()->quoteLevel1DefaultTextColor(), |
|
MessageCore::ColorUtil::self()->quoteLevel2DefaultTextColor(), |
|
MessageCore::ColorUtil::self()->quoteLevel3DefaultTextColor(), |
|
MessageCore::ColorUtil::self()->linkColor(), // link |
|
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 |
|
Qt::white // colorbar html fg |
|
}; |
|
|
|
for (int i = 0; i < numColorNames; ++i) { |
|
if (loadFromConfig) { |
|
const QString configName = QLatin1String(colorNames[i].configName); |
|
if (configName == QLatin1String("UnreadMessageColor")) { |
|
mColorList->setColorSilently(i, MessageList::MessageListSettings::self()->unreadMessageColor()); |
|
} else if (configName == QLatin1String("ImportantMessageColor")) { |
|
mColorList->setColorSilently(i, MessageList::MessageListSettings::self()->importantMessageColor()); |
|
} else if (configName == QLatin1String("TodoMessageColor")) { |
|
mColorList->setColorSilently(i, MessageList::MessageListSettings::self()->todoMessageColor()); |
|
} else { |
|
mColorList->setColorSilently(i, reader.readEntry(configName, defaultColor[i])); |
|
} |
|
} else { |
|
mColorList->setColorSilently(i, defaultColor[i]); |
|
} |
|
} |
|
} else { |
|
setEnabled(false); |
|
} |
|
} |
|
|
|
void AppearancePage::ColorsTab::doResetToDefaultsOther() |
|
{ |
|
mCustomColorCheck->setChecked(false); |
|
mUseInlineStyle->setChecked(false); |
|
mRecycleColorCheck->setChecked(false); |
|
mCloseToQuotaThreshold->setValue(80); |
|
loadColor(false); |
|
} |
|
|
|
void AppearancePage::ColorsTab::save() |
|
{ |
|
if (!KMKernel::self()) { |
|
return; |
|
} |
|
KConfigGroup reader(KMKernel::self()->config(), "Reader"); |
|
bool customColors = mCustomColorCheck->isChecked(); |
|
MessageCore::MessageCoreSettings::self()->setUseDefaultColors(!customColors); |
|
MessageCore::MessageCoreSettings::self()->setUseRealHtmlMailColor(mUseInlineStyle->isChecked()); |
|
|
|
for (int i = 0; i < numColorNames; ++i) { |
|
const QString configName = QLatin1String(colorNames[i].configName); |
|
if (customColors && configName == QLatin1String("UnreadMessageColor")) { |
|
MessageList::MessageListSettings::self()->setUnreadMessageColor(mColorList->color(i)); |
|
} else if (customColors && configName == QLatin1String("ImportantMessageColor")) { |
|
MessageList::MessageListSettings::self()->setImportantMessageColor(mColorList->color(i)); |
|
} else if (customColors && configName == QLatin1String("TodoMessageColor")) { |
|
MessageList::MessageListSettings::self()->setTodoMessageColor(mColorList->color(i)); |
|
} else { |
|
if (customColors || reader.hasKey(configName)) { |
|
reader.writeEntry(configName, mColorList->color(i)); |
|
} |
|
} |
|
} |
|
MessageViewer::MessageViewerSettings::self()->setRecycleQuoteColors(mRecycleColorCheck->isChecked()); |
|
KMailSettings::self()->setCloseToQuotaThreshold(mCloseToQuotaThreshold->value()); |
|
} |
|
|
|
QString AppearancePage::LayoutTab::helpAnchor() const |
|
{ |
|
return QStringLiteral("configure-appearance-layout"); |
|
} |
|
|
|
AppearancePageLayoutTab::AppearancePageLayoutTab(QWidget *parent) |
|
: ConfigModuleTab(parent) |
|
{ |
|
auto *vlay = new QVBoxLayout(this); |
|
|
|
// "folder list" radio buttons: |
|
populateButtonGroup(mFolderListGroupBox = new QGroupBox(this), |
|
mFolderListGroup = new QButtonGroup(this), |
|
Qt::Vertical, KMailSettings::self()->folderListItem()); |
|
vlay->addWidget(mFolderListGroupBox); |
|
connect(mFolderListGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
auto *folderCBHLayout = new QHBoxLayout; |
|
mFolderQuickSearchCB = new QCheckBox(i18n("Show folder quick search field"), this); |
|
connect(mFolderQuickSearchCB, &QAbstractButton::toggled, this, &ConfigModuleTab::slotEmitChanged); |
|
folderCBHLayout->addWidget(mFolderQuickSearchCB); |
|
vlay->addLayout(folderCBHLayout); |
|
|
|
// "favorite folders view mode" radio buttons: |
|
mFavoriteFoldersViewGroupBox = new QGroupBox(this); |
|
mFavoriteFoldersViewGroupBox->setTitle(i18n("Show Favorite Folders View")); |
|
mFavoriteFoldersViewGroupBox->setLayout(new QVBoxLayout()); |
|
mFavoriteFoldersViewGroup = new QButtonGroup(this); |
|
connect(mFavoriteFoldersViewGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
QRadioButton *favoriteFoldersViewHiddenRadio = new QRadioButton(i18n("Never"), mFavoriteFoldersViewGroupBox); |
|
mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewHiddenRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode)); |
|
mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewHiddenRadio); |
|
|
|
QRadioButton *favoriteFoldersViewIconsRadio = new QRadioButton(i18n("As icons"), mFavoriteFoldersViewGroupBox); |
|
mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewIconsRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode)); |
|
mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewIconsRadio); |
|
|
|
QRadioButton *favoriteFoldersViewListRadio = new QRadioButton(i18n("As list"), mFavoriteFoldersViewGroupBox); |
|
mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewListRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode)); |
|
mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewListRadio); |
|
|
|
vlay->addWidget(mFavoriteFoldersViewGroupBox); |
|
|
|
// "folder tooltips" radio buttons: |
|
mFolderToolTipsGroupBox = new QGroupBox(this); |
|
mFolderToolTipsGroupBox->setTitle(i18n("Folder Tooltips")); |
|
mFolderToolTipsGroupBox->setLayout(new QVBoxLayout()); |
|
mFolderToolTipsGroup = new QButtonGroup(this); |
|
connect(mFolderToolTipsGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
QRadioButton *folderToolTipsAlwaysRadio = new QRadioButton(i18n("Always"), mFolderToolTipsGroupBox); |
|
mFolderToolTipsGroup->addButton(folderToolTipsAlwaysRadio, static_cast< int >(FolderTreeWidget::DisplayAlways)); |
|
mFolderToolTipsGroupBox->layout()->addWidget(folderToolTipsAlwaysRadio); |
|
|
|
QRadioButton *folderToolTipsNeverRadio = new QRadioButton(i18n("Never"), mFolderToolTipsGroupBox); |
|
mFolderToolTipsGroup->addButton(folderToolTipsNeverRadio, static_cast< int >(FolderTreeWidget::DisplayNever)); |
|
mFolderToolTipsGroupBox->layout()->addWidget(folderToolTipsNeverRadio); |
|
|
|
vlay->addWidget(mFolderToolTipsGroupBox); |
|
|
|
// "show reader window" radio buttons: |
|
populateButtonGroup(mReaderWindowModeGroupBox = new QGroupBox(this), |
|
mReaderWindowModeGroup = new QButtonGroup(this), |
|
Qt::Vertical, KMailSettings::self()->readerWindowModeItem()); |
|
vlay->addWidget(mReaderWindowModeGroupBox); |
|
|
|
connect(mReaderWindowModeGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
vlay->addStretch(10); // spacer |
|
} |
|
|
|
void AppearancePage::LayoutTab::doLoadOther() |
|
{ |
|
loadWidget(mFolderListGroupBox, mFolderListGroup, KMailSettings::self()->folderListItem()); |
|
loadWidget(mReaderWindowModeGroupBox, mReaderWindowModeGroup, KMailSettings::self()->readerWindowModeItem()); |
|
if (KMKernel::self()) { |
|
loadWidget(mFavoriteFoldersViewGroupBox, mFavoriteFoldersViewGroup, KMKernel::self()->mailCommonSettings()->favoriteCollectionViewModeItem()); |
|
} |
|
loadWidget(mFolderQuickSearchCB, KMailSettings::self()->enableFolderQuickSearchItem()); |
|
const int checkedFolderToolTipsPolicy = KMailSettings::self()->toolTipDisplayPolicy(); |
|
if (checkedFolderToolTipsPolicy >= 0) { |
|
mFolderToolTipsGroup->button(checkedFolderToolTipsPolicy)->setChecked(true); |
|
} |
|
} |
|
|
|
void AppearancePage::LayoutTab::save() |
|
{ |
|
saveButtonGroup(mFolderListGroup, KMailSettings::self()->folderListItem()); |
|
saveButtonGroup(mReaderWindowModeGroup, KMailSettings::self()->readerWindowModeItem()); |
|
if (KMKernel::self()) { |
|
saveButtonGroup(mFavoriteFoldersViewGroup, KMKernel::self()->mailCommonSettings()->favoriteCollectionViewModeItem()); |
|
} |
|
saveCheckBox(mFolderQuickSearchCB, KMailSettings::self()->enableFolderQuickSearchItem()); |
|
KMailSettings::self()->setToolTipDisplayPolicy(mFolderToolTipsGroup->checkedId()); |
|
} |
|
|
|
// |
|
// Appearance Message List |
|
// |
|
|
|
QString AppearancePage::HeadersTab::helpAnchor() const |
|
{ |
|
return QStringLiteral("configure-appearance-headers"); |
|
} |
|
|
|
static const struct { |
|
const char *displayName; |
|
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 } |
|
}; |
|
static const int numDateDisplayConfig |
|
= sizeof dateDisplayConfig / sizeof *dateDisplayConfig; |
|
|
|
AppearancePageHeadersTab::AppearancePageHeadersTab(QWidget *parent) |
|
: ConfigModuleTab(parent) |
|
{ |
|
auto *vlay = new QVBoxLayout(this); |
|
|
|
// "General Options" group: |
|
QGroupBox *group = new QGroupBox(i18nc("General options for the message list.", "General"), this); |
|
auto *gvlay = new QVBoxLayout(group); |
|
|
|
mDisplayMessageToolTips = new QCheckBox( |
|
MessageList::MessageListSettings::self()->messageToolTipEnabledItem()->label(), group); |
|
gvlay->addWidget(mDisplayMessageToolTips); |
|
|
|
connect(mDisplayMessageToolTips, &QCheckBox::stateChanged, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
// "Aggregation" |
|
using MessageList::Utils::AggregationComboBox; |
|
mAggregationComboBox = new AggregationComboBox(group); |
|
|
|
QLabel *aggregationLabel = new QLabel(i18n("Default aggregation:"), group); |
|
aggregationLabel->setBuddy(mAggregationComboBox); |
|
|
|
using MessageList::Utils::AggregationConfigButton; |
|
auto *aggregationConfigButton = new AggregationConfigButton(group, mAggregationComboBox); |
|
|
|
auto *aggregationLayout = new QHBoxLayout(); |
|
aggregationLayout->addWidget(aggregationLabel, 1); |
|
aggregationLayout->addWidget(mAggregationComboBox, 1); |
|
aggregationLayout->addWidget(aggregationConfigButton, 0); |
|
gvlay->addLayout(aggregationLayout); |
|
|
|
connect(aggregationConfigButton, &MessageList::Utils::AggregationConfigButton::configureDialogCompleted, |
|
this, &AppearancePageHeadersTab::slotSelectDefaultAggregation); |
|
connect(mAggregationComboBox, qOverload<int>(&MessageList::Utils::AggregationComboBox::activated), |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
// "Theme" |
|
using MessageList::Utils::ThemeComboBox; |
|
mThemeComboBox = new ThemeComboBox(group); |
|
|
|
QLabel *themeLabel = new QLabel(i18n("Default theme:"), group); |
|
themeLabel->setBuddy(mThemeComboBox); |
|
|
|
using MessageList::Utils::ThemeConfigButton; |
|
auto *themeConfigButton = new ThemeConfigButton(group, mThemeComboBox); |
|
|
|
auto *themeLayout = new QHBoxLayout(); |
|
themeLayout->addWidget(themeLabel, 1); |
|
themeLayout->addWidget(mThemeComboBox, 1); |
|
themeLayout->addWidget(themeConfigButton, 0); |
|
gvlay->addLayout(themeLayout); |
|
|
|
connect(themeConfigButton, &MessageList::Utils::ThemeConfigButton::configureDialogCompleted, |
|
this, &AppearancePageHeadersTab::slotSelectDefaultTheme); |
|
connect(mThemeComboBox, qOverload<int>(&MessageList::Utils::ThemeComboBox::activated), |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
vlay->addWidget(group); |
|
|
|
// "Date Display" group: |
|
mDateDisplayBox = new QGroupBox(this); |
|
mDateDisplayBox->setTitle(i18n("Date Display")); |
|
mDateDisplay = new QButtonGroup(this); |
|
mDateDisplay->setExclusive(true); |
|
gvlay = new QVBoxLayout(mDateDisplayBox); |
|
|
|
for (int i = 0; i < numDateDisplayConfig; ++i) { |
|
const char *label = dateDisplayConfig[i].displayName; |
|
QString buttonLabel; |
|
if (QString::fromLatin1(label).contains(QLatin1String("%1"))) { |
|
buttonLabel = i18n(label, DateFormatter::formatCurrentDate(dateDisplayConfig[i].dateDisplay)); |
|
} else { |
|
buttonLabel = i18n(label); |
|
} |
|
if (dateDisplayConfig[i].dateDisplay == DateFormatter::Custom) { |
|
QWidget *hbox = new QWidget(mDateDisplayBox); |
|
auto *hboxHBoxLayout = new QHBoxLayout(hbox); |
|
hboxHBoxLayout->setContentsMargins({}); |
|
auto *radio = new QRadioButton(buttonLabel, hbox); |
|
hboxHBoxLayout->addWidget(radio); |
|
mDateDisplay->addButton(radio, dateDisplayConfig[i].dateDisplay); |
|
|
|
mCustomDateFormatEdit = new QLineEdit(hbox); |
|
new KPIM::LineEditCatchReturnKey(mCustomDateFormatEdit, this); |
|
hboxHBoxLayout->addWidget(mCustomDateFormatEdit); |
|
mCustomDateFormatEdit->setEnabled(false); |
|
hboxHBoxLayout->setStretchFactor(mCustomDateFormatEdit, 1); |
|
|
|
connect(radio, &QAbstractButton::toggled, |
|
mCustomDateFormatEdit, &QWidget::setEnabled); |
|
connect(mCustomDateFormatEdit, &QLineEdit::textChanged, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
QLabel *formatHelp = new QLabel( |
|
i18n("<qt><a href=\"whatsthis1\">Custom format information...</a></qt>"), hbox); |
|
formatHelp->setContextMenuPolicy(Qt::NoContextMenu); |
|
connect(formatHelp, &QLabel::linkActivated, |
|
this, &AppearancePageHeadersTab::slotLinkClicked); |
|
hboxHBoxLayout->addWidget(formatHelp); |
|
|
|
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>"); |
|
mCustomDateFormatEdit->setWhatsThis(mCustomDateWhatsThis); |
|
radio->setWhatsThis(mCustomDateWhatsThis); |
|
gvlay->addWidget(hbox); |
|
} else { |
|
auto *radio = new QRadioButton(buttonLabel, mDateDisplayBox); |
|
gvlay->addWidget(radio); |
|
mDateDisplay->addButton(radio, dateDisplayConfig[i].dateDisplay); |
|
} |
|
} // end for loop populating mDateDisplay |
|
|
|
vlay->addWidget(mDateDisplayBox); |
|
connect(mDateDisplay, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
vlay->addStretch(10); // spacer |
|
} |
|
|
|
void AppearancePageHeadersTab::slotLinkClicked(const QString &link) |
|
{ |
|
if (link == QLatin1String("whatsthis1")) { |
|
QWhatsThis::showText(QCursor::pos(), mCustomDateWhatsThis); |
|
} |
|
} |
|
|
|
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": |
|
loadWidget(mDisplayMessageToolTips, MessageList::MessageListSettings::self()->messageToolTipEnabledItem()); |
|
|
|
// "Aggregation": |
|
slotSelectDefaultAggregation(); |
|
|
|
// "Theme": |
|
slotSelectDefaultTheme(); |
|
|
|
// "Date Display": |
|
setDateDisplay(MessageCore::MessageCoreSettings::self()->dateFormat(), |
|
MessageCore::MessageCoreSettings::self()->customDateFormat()); |
|
} |
|
|
|
void AppearancePage::HeadersTab::doLoadFromGlobalSettings() |
|
{ |
|
loadWidget(mDisplayMessageToolTips, MessageList::MessageListSettings::self()->messageToolTipEnabledItem()); |
|
// "Aggregation": |
|
slotSelectDefaultAggregation(); |
|
|
|
// "Theme": |
|
slotSelectDefaultTheme(); |
|
|
|
setDateDisplay(MessageCore::MessageCoreSettings::self()->dateFormat(), |
|
MessageCore::MessageCoreSettings::self()->customDateFormat()); |
|
} |
|
|
|
void AppearancePage::HeadersTab::setDateDisplay(int num, const QString &format) |
|
{ |
|
auto dateDisplay |
|
= static_cast<DateFormatter::FormatType>(num); |
|
|
|
// special case: needs text for the line edit: |
|
if (dateDisplay == DateFormatter::Custom) { |
|
mCustomDateFormatEdit->setText(format); |
|
} |
|
|
|
for (int i = 0; i < numDateDisplayConfig; ++i) { |
|
if (dateDisplay == dateDisplayConfig[i].dateDisplay) { |
|
mDateDisplay->button(dateDisplay)->setChecked(true); |
|
return; |
|
} |
|
} |
|
// fell through since none found: |
|
mDateDisplay->button(numDateDisplayConfig - 2)->setChecked(true); // default |
|
} |
|
|
|
void AppearancePage::HeadersTab::save() |
|
{ |
|
saveCheckBox(mDisplayMessageToolTips, MessageList::MessageListSettings::self()->messageToolTipEnabledItem()); |
|
|
|
if (KMKernel::self()) { |
|
KMKernel::self()->savePaneSelection(); |
|
} |
|
// "Aggregation" |
|
mAggregationComboBox->writeDefaultConfig(); |
|
|
|
// "Theme" |
|
mThemeComboBox->writeDefaultConfig(); |
|
|
|
const int dateDisplayID = mDateDisplay->checkedId(); |
|
MessageCore::MessageCoreSettings::self()->setDateFormat(dateDisplayID); |
|
MessageCore::MessageCoreSettings::self()->setCustomDateFormat(mCustomDateFormatEdit->text()); |
|
} |
|
|
|
// |
|
// Message Window |
|
// |
|
|
|
QString AppearancePage::ReaderTab::helpAnchor() const |
|
{ |
|
return QStringLiteral("configure-appearance-reader"); |
|
} |
|
|
|
AppearancePageGeneralTab::AppearancePageGeneralTab(QWidget *parent) |
|
: ConfigModuleTab(parent) |
|
{ |
|
auto *topLayout = new QVBoxLayout(this); |
|
|
|
QGroupBox *readerBox = new QGroupBox(i18n("Message Window"), this); |
|
topLayout->addWidget(readerBox); |
|
|
|
auto *readerBoxLayout = new QVBoxLayout(readerBox); |
|
|
|
// "Close message window after replying or forwarding" check box: |
|
populateCheckBox(mCloseAfterReplyOrForwardCheck = new QCheckBox(this), |
|
MessageViewer::MessageViewerSettings::self()->closeAfterReplyOrForwardItem()); |
|
mCloseAfterReplyOrForwardCheck->setToolTip( |
|
i18n("Close the standalone message window after replying or forwarding the message")); |
|
readerBoxLayout->addWidget(mCloseAfterReplyOrForwardCheck); |
|
connect(mCloseAfterReplyOrForwardCheck, &QCheckBox::stateChanged, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
|
|
mViewerSettings = new MessageViewer::ConfigureWidget; |
|
connect(mViewerSettings, &MessageViewer::ConfigureWidget::settingsChanged, |
|
this, &ConfigModuleTab::slotEmitChanged); |
|
readerBoxLayout->addWidget(mViewerSettings); |
|
|
|
QGroupBox *systrayBox = new QGroupBox(i18n("System Tray"), this); |
|
topLayout->addWidget(systrayBox); |
|
|
|
auto *systrayBoxlayout = new QVBoxLayout(systrayBox); |
|
|
|
// "Enable system tray applet" check box |
|
mSystemTrayCheck = new QCheckBox(i18n("Enable system tray icon"), this); |
|
systrayBoxlayout->addWidget(mSystemTrayCheck); |
|
|
|
// "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) { |
|
if (state == Qt::Checked) { |
|
mSystemTrayCheck->setCheckState(Qt::Checked); |
|
} |
|
slotEmitChanged(); |
|
}); |
|
connect(mSystemTrayCheck, &QCheckBox::stateChanged, this, [this](int state) { |
|
if (state == Qt::Unchecked) { |
|
mStartInTrayCheck->setCheckState(Qt::Unchecked); |
|
} |
|
slotEmitChanged(); |
|
}); |
|
|
|
// "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); |
|
|
|
topLayout->addStretch(100); // spacer |
|
} |
|
|
|
void AppearancePage::ReaderTab::doResetToDefaultsOther() |
|
{ |
|
} |
|
|
|
void AppearancePage::ReaderTab::doLoadOther() |
|
{ |
|
loadWidget(mSystemTrayCheck, KMailSettings::self()->systemTrayEnabledItem()); |
|
loadWidget(mStartInTrayCheck, KMailSettings::self()->startInTrayItem()); |
|
loadWidget(mShowNumberInTaskBar, KMailSettings::self()->showUnreadInTaskbarItem()); |
|
loadWidget(mCloseAfterReplyOrForwardCheck, MessageViewer::MessageViewerSettings::self()->closeAfterReplyOrForwardItem()); |
|
mViewerSettings->readConfig(); |
|
} |
|
|
|
void AppearancePage::ReaderTab::save() |
|
{ |
|
saveCheckBox(mSystemTrayCheck, KMailSettings::self()->systemTrayEnabledItem()); |
|
saveCheckBox(mStartInTrayCheck, KMailSettings::self()->startInTrayItem()); |
|
saveCheckBox(mShowNumberInTaskBar, KMailSettings::self()->showUnreadInTaskbarItem()); |
|
KMailSettings::self()->save(); |
|
saveCheckBox(mCloseAfterReplyOrForwardCheck, MessageViewer::MessageViewerSettings::self()->closeAfterReplyOrForwardItem()); |
|
mViewerSettings->writeConfig(); |
|
} |
|
|
|
QString AppearancePage::MessageTagTab::helpAnchor() const |
|
{ |
|
return QStringLiteral("configure-appearance-messagetag"); |
|
} |
|
|
|
TagListWidgetItem::TagListWidgetItem(QListWidget *parent) |
|
: QListWidgetItem(parent) |
|
, mTag(nullptr) |
|
{ |
|
} |
|
|
|
TagListWidgetItem::TagListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent) |
|
: QListWidgetItem(icon, text, parent) |
|
, mTag(nullptr) |
|
{ |
|
} |
|
|
|
TagListWidgetItem::~TagListWidgetItem() |
|
= default; |
|
|
|
void TagListWidgetItem::setKMailTag(const MailCommon::Tag::Ptr &tag) |
|
{ |
|
mTag = tag; |
|
} |
|
|
|
MailCommon::Tag::Ptr TagListWidgetItem::kmailTag() const |
|
{ |
|
return mTag; |
|
} |
|
|
|
AppearancePageMessageTagTab::AppearancePageMessageTagTab(QWidget *parent) |
|
: ConfigModuleTab(parent) |
|
{ |
|
mPreviousTag = -1; |
|
auto *maingrid = new QHBoxLayout(this); |
|
|
|
//Lefthand side Listbox and friends |
|
|
|
//Groupbox frame |
|
mTagsGroupBox = new QGroupBox(i18n("A&vailable Tags"), this); |
|
maingrid->addWidget(mTagsGroupBox); |
|
auto *tageditgrid = new QVBoxLayout(mTagsGroupBox); |
|
|
|
//Listbox, add, remove row |
|
auto *addremovegrid = new QHBoxLayout(); |
|
tageditgrid->addLayout(addremovegrid); |
|
|
|
mTagAddLineEdit = new QLineEdit(mTagsGroupBox); |
|
new KPIM::LineEditCatchReturnKey(mTagAddLineEdit, this); |
|
addremovegrid->addWidget(mTagAddLineEdit); |
|
|
|
mTagAddButton = new QPushButton(mTagsGroupBox); |
|
mTagAddButton->setToolTip(i18n("Add new tag")); |
|
mTagAddButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); |
|
addremovegrid->addWidget(mTagAddButton); |
|
|
|
mTagRemoveButton = new QPushButton(mTagsGroupBox); |
|
mTagRemoveButton->setToolTip(i18n("Remove selected tag")); |
|
mTagRemoveButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); |
|
addremovegrid->addWidget(mTagRemoveButton); |
|
|
|
//Up and down buttons |
|
auto *updowngrid = new QHBoxLayout(); |
|
tageditgrid->addLayout(updowngrid); |
|
|
|
mTagUpButton = new QPushButton(mTagsGroupBox); |
|
mTagUpButton->setToolTip(i18n("Increase tag priority")); |
|
mTagUpButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up"))); |
|
mTagUpButton->setAutoRepeat(true); |
|
updowngrid->addWidget(mTagUpButton); |
|
|
|
mTagDownButton = new QPushButton(mTagsGroupBox); |
|
mTagDownButton->setToolTip(i18n("Decrease tag priority")); |
|
mTagDownButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down"))); |
|
mTagDownButton->setAutoRepeat(true); |
|
updowngrid->addWidget(mTagDownButton); |
|
|
|
//Listbox for tag names |
|
auto *listboxgrid = new QHBoxLayout(); |
|
tageditgrid->addLayout(listboxgrid); |
|
mTagListBox = new QListWidget(mTagsGroupBox); |
|
mTagListBox->setDragDropMode(QAbstractItemView::InternalMove); |
|
connect(mTagListBox->model(), &QAbstractItemModel::rowsMoved, this, &AppearancePageMessageTagTab::slotRowsMoved); |
|
|
|
mTagListBox->setMinimumWidth(150); |
|
listboxgrid->addWidget(mTagListBox); |
|
|
|
//RHS for individual tag settings |
|
|
|
//Extra VBoxLayout for stretchers around settings |
|
auto *tagsettinggrid = new QVBoxLayout(); |
|
maingrid->addLayout(tagsettinggrid); |
|
|
|
//Groupbox frame |
|
mTagSettingGroupBox = new QGroupBox(i18n("Ta&g Settings"), |
|
this); |
|
tagsettinggrid->addWidget(mTagSettingGroupBox); |
|
QList<KActionCollection *> actionCollections; |
|
if (kmkernel->getKMMainWidget()) { |
|
actionCollections = kmkernel->getKMMainWidget()->actionCollections(); |
|
} |
|
|
|
auto *lay = new QHBoxLayout(mTagSettingGroupBox); |
|
mTagWidget = new MailCommon::TagWidget(actionCollections, this); |
|
lay->addWidget(mTagWidget); |
|
|
|
connect(mTagWidget, &TagWidget::changed, this, &AppearancePageMessageTagTab::slotEmitChangeCheck); |
|
|
|
//For enabling the add button in case box is non-empty |
|
connect(mTagAddLineEdit, &QLineEdit::textChanged, |
|
this, &AppearancePage::MessageTagTab::slotAddLineTextChanged); |
|
|
|
//For on-the-fly updating of tag name in editbox |
|
connect(mTagWidget->tagNameLineEdit(), &QLineEdit::textChanged, |
|
this, &AppearancePageMessageTagTab::slotNameLineTextChanged); |
|
|
|
connect(mTagWidget, &TagWidget::iconNameChanged, this, &AppearancePageMessageTagTab::slotIconNameChanged); |
|
|
|
connect(mTagAddLineEdit, &QLineEdit::returnPressed, |
|
this, &AppearancePageMessageTagTab::slotAddNewTag); |
|
|
|
connect(mTagAddButton, &QAbstractButton::clicked, |
|
this, &AppearancePageMessageTagTab::slotAddNewTag); |
|
|
|
connect(mTagRemoveButton, &QAbstractButton::clicked, |
|
this, &AppearancePageMessageTagTab::slotRemoveTag); |
|
|
|
connect(mTagUpButton, &QAbstractButton::clicked, |
|
this, &AppearancePageMessageTagTab::slotMoveTagUp); |
|
|
|
connect(mTagDownButton, &QAbstractButton::clicked, |
|
this, &AppearancePageMessageTagTab::slotMoveTagDown); |
|
|
|
connect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
//Adjust widths for columns |
|
maingrid->setStretchFactor(mTagsGroupBox, 1); |
|
maingrid->setStretchFactor(lay, 1); |
|
tagsettinggrid->addStretch(10); |
|
} |
|
|
|
AppearancePageMessageTagTab::~AppearancePageMessageTagTab() |
|
= default; |
|
|
|
void AppearancePage::MessageTagTab::slotEmitChangeCheck() |
|
{ |
|
slotEmitChanged(); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotRowsMoved(const QModelIndex &, int sourcestart, int sourceEnd, const QModelIndex &, int destinationRow) |
|
{ |
|
Q_UNUSED(sourceEnd); |
|
Q_UNUSED(sourcestart); |
|
Q_UNUSED(destinationRow); |
|
updateButtons(); |
|
slotEmitChangeCheck(); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::updateButtons() |
|
{ |
|
const int currentIndex = mTagListBox->currentRow(); |
|
|
|
const bool theFirst = (currentIndex == 0); |
|
const bool theLast = (currentIndex >= (int)mTagListBox->count() - 1); |
|
const bool aFilterIsSelected = (currentIndex >= 0); |
|
|
|
mTagUpButton->setEnabled(aFilterIsSelected && !theFirst); |
|
mTagDownButton->setEnabled(aFilterIsSelected && !theLast); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotMoveTagUp() |
|
{ |
|
const int tmp_index = mTagListBox->currentRow(); |
|
if (tmp_index <= 0) { |
|
return; |
|
} |
|
swapTagsInListBox(tmp_index, tmp_index - 1); |
|
updateButtons(); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotMoveTagDown() |
|
{ |
|
const int tmp_index = mTagListBox->currentRow(); |
|
if ((tmp_index < 0) |
|
|| (tmp_index >= int(mTagListBox->count()) - 1)) { |
|
return; |
|
} |
|
swapTagsInListBox(tmp_index, tmp_index + 1); |
|
updateButtons(); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::swapTagsInListBox(const int first, const int second) |
|
{ |
|
disconnect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
QListWidgetItem *item = mTagListBox->takeItem(first); |
|
// now selected item is at idx(idx-1), so |
|
// insert the other item at idx, ie. above(below). |
|
mPreviousTag = second; |
|
mTagListBox->insertItem(second, item); |
|
mTagListBox->setCurrentRow(second); |
|
connect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
slotEmitChangeCheck(); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotRecordTagSettings(int aIndex) |
|
{ |
|
if ((aIndex < 0) || (aIndex >= int(mTagListBox->count()))) { |
|
return; |
|
} |
|
QListWidgetItem *item = mTagListBox->item(aIndex); |
|
auto *tagItem = static_cast<TagListWidgetItem *>(item); |
|
|
|
MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag(); |
|
|
|
tmp_desc->tagName = tagItem->text(); |
|
mTagWidget->recordTagSettings(tmp_desc); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotUpdateTagSettingWidgets(int aIndex) |
|
{ |
|
//Check if selection is valid |
|
if ((aIndex < 0) || (mTagListBox->currentRow() < 0)) { |
|
mTagRemoveButton->setEnabled(false); |
|
mTagUpButton->setEnabled(false); |
|
mTagDownButton->setEnabled(false); |
|
|
|
mTagWidget->setEnabled(false); |
|
return; |
|
} |
|
mTagWidget->setEnabled(true); |
|
|
|
mTagRemoveButton->setEnabled(true); |
|
mTagUpButton->setEnabled((0 != aIndex)); |
|
mTagDownButton->setEnabled(((int(mTagListBox->count()) - 1) != aIndex)); |
|
QListWidgetItem *item = mTagListBox->currentItem(); |
|
auto *tagItem = static_cast<TagListWidgetItem *>(item); |
|
MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag(); |
|
|
|
disconnect(mTagWidget->tagNameLineEdit(), &QLineEdit::textChanged, |
|
this, &AppearancePage::MessageTagTab::slotNameLineTextChanged); |
|
|
|
mTagWidget->tagNameLineEdit()->setEnabled(!tmp_desc->isImmutable); |
|
mTagWidget->tagNameLineEdit()->setText(tmp_desc->tagName); |
|
connect(mTagWidget->tagNameLineEdit(), &QLineEdit::textChanged, |
|
this, &AppearancePage::MessageTagTab::slotNameLineTextChanged); |
|
|
|
mTagWidget->setTagTextColor(tmp_desc->textColor); |
|
|
|
mTagWidget->setTagBackgroundColor(tmp_desc->backgroundColor); |
|
|
|
mTagWidget->setTagTextFormat(tmp_desc->isBold, tmp_desc->isItalic); |
|
|
|
mTagWidget->iconButton()->setEnabled(!tmp_desc->isImmutable); |
|
mTagWidget->iconButton()->setIcon(tmp_desc->iconName); |
|
|
|
mTagWidget->keySequenceWidget()->setEnabled(true); |
|
mTagWidget->keySequenceWidget()->setKeySequence(tmp_desc->shortcut, |
|
KKeySequenceWidget::NoValidate); |
|
|
|
mTagWidget->inToolBarCheck()->setEnabled(true); |
|
mTagWidget->inToolBarCheck()->setChecked(tmp_desc->inToolbar); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotSelectionChanged() |
|
{ |
|
mEmitChanges = false; |
|
slotRecordTagSettings(mPreviousTag); |
|
slotUpdateTagSettingWidgets(mTagListBox->currentRow()); |
|
mPreviousTag = mTagListBox->currentRow(); |
|
mEmitChanges = true; |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotRemoveTag() |
|
{ |
|
const int tmp_index = mTagListBox->currentRow(); |
|
if (tmp_index >= 0) { |
|
if (KMessageBox::Yes == KMessageBox::questionYesNo(this, i18n("Do you want to remove tag \'%1\'?", mTagListBox->item(mTagListBox->currentRow())->text()))) { |
|
QListWidgetItem *item = mTagListBox->takeItem(mTagListBox->currentRow()); |
|
auto *tagItem = static_cast<TagListWidgetItem *>(item); |
|
MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag(); |
|
if (tmp_desc->tag().isValid()) { |
|
new Akonadi::TagDeleteJob(tmp_desc->tag()); |
|
} else { |
|
qCWarning(KMAIL_LOG) << "Can't remove tag with invalid akonadi tag"; |
|
} |
|
mPreviousTag = -1; |
|
|
|
//Before deleting the current item, make sure the selectionChanged signal |
|
//is disconnected, so that the widgets will not get updated while the |
|
//deletion takes place. |
|
disconnect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
|
|
delete item; |
|
connect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
|
|
slotSelectionChanged(); |
|
slotEmitChangeCheck(); |
|
} |
|
} |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotDeleteTagJob(KJob *job) |
|
{ |
|
if (job->error()) { |
|
qCWarning(KMAIL_LOG) << "Failed to delete tag " << job->errorString(); |
|
} |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotNameLineTextChanged(const QString &aText) |
|
{ |
|
//If deleted all, leave the first character for the sake of not having an |
|
//empty tag name |
|
if (aText.isEmpty() && !mTagListBox->currentItem()) { |
|
return; |
|
} |
|
|
|
const int count = mTagListBox->count(); |
|
for (int i = 0; i < count; ++i) { |
|
if (mTagListBox->item(i)->text() == aText) { |
|
KMessageBox::error(this, i18n("We cannot create tag. A tag with same name already exists.")); |
|
disconnect(mTagWidget->tagNameLineEdit(), &QLineEdit::textChanged, |
|
this, &AppearancePageMessageTagTab::slotNameLineTextChanged); |
|
mTagWidget->tagNameLineEdit()->setText(mTagListBox->currentItem()->text()); |
|
connect(mTagWidget->tagNameLineEdit(), &QLineEdit::textChanged, |
|
this, &AppearancePageMessageTagTab::slotNameLineTextChanged); |
|
return; |
|
} |
|
} |
|
|
|
//Disconnect so the tag information is not saved and reloaded with every |
|
//letter |
|
disconnect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
|
|
mTagListBox->currentItem()->setText(aText); |
|
connect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotIconNameChanged(const QString &iconName) |
|
{ |
|
mTagListBox->currentItem()->setIcon(QIcon::fromTheme(iconName)); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotAddLineTextChanged(const QString &aText) |
|
{ |
|
mTagAddButton->setEnabled(!aText.trimmed().isEmpty()); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotAddNewTag() |
|
{ |
|
const QString newTagName = mTagAddLineEdit->text().trimmed(); |
|
if (newTagName.isEmpty()) { |
|
return; |
|
} |
|
const int count = mTagListBox->count(); |
|
for (int i = 0; i < count; ++i) { |
|
if (mTagListBox->item(i)->text() == newTagName) { |
|
KMessageBox::error(this, i18n("We cannot create tag. A tag with same name already exists.")); |
|
return; |
|
} |
|
} |
|
|
|
const int tmp_priority = mTagListBox->count(); |
|
|
|
MailCommon::Tag::Ptr tag(Tag::createDefaultTag(newTagName)); |
|
tag->priority = tmp_priority; |
|
|
|
slotEmitChangeCheck(); |
|
TagListWidgetItem *newItem = new TagListWidgetItem(QIcon::fromTheme(tag->iconName), newTagName, mTagListBox); |
|
newItem->setKMailTag(tag); |
|
mTagListBox->addItem(newItem); |
|
mTagListBox->setCurrentItem(newItem); |
|
mTagAddLineEdit->clear(); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::doLoadFromGlobalSettings() |
|
{ |
|
mTagListBox->clear(); |
|
|
|
auto *fetchJob = new Akonadi::TagFetchJob(this); |
|
fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>(); |
|
connect(fetchJob, &KJob::result, this, &AppearancePageMessageTagTab::slotTagsFetched); |
|
} |
|
|
|
void AppearancePage::MessageTagTab::slotTagsFetched(KJob *job) |
|
{ |
|
if (job->error()) { |
|
qCWarning(KMAIL_LOG) << "Failed to load tags " << job->errorString(); |
|
return; |
|
} |
|
auto *fetchJob = static_cast<Akonadi::TagFetchJob *>(job); |
|
|
|
QList<MailCommon::TagPtr> msgTagList; |
|
const Akonadi::Tag::List tagList = fetchJob->tags(); |
|
msgTagList.reserve(tagList.count()); |
|
for (const Akonadi::Tag &akonadiTag : tagList) { |
|
MailCommon::Tag::Ptr tag = MailCommon::Tag::fromAkonadi(akonadiTag); |
|
msgTagList.append(tag); |
|
} |
|
|
|
std::sort(msgTagList.begin(), msgTagList.end(), MailCommon::Tag::compare); |
|
|
|
for (const MailCommon::Tag::Ptr &tag : qAsConst(msgTagList)) { |
|
TagListWidgetItem *newItem = new TagListWidgetItem(QIcon::fromTheme(tag->iconName), tag->tagName, mTagListBox); |
|
newItem->setKMailTag(tag); |
|
if (tag->priority == -1) { |
|
tag->priority = mTagListBox->count() - 1; |
|
} |
|
} |
|
|
|
//Disconnect so that insertItem's do not trigger an update procedure |
|
disconnect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
|
|
connect(mTagListBox, &QListWidget::currentItemChanged, |
|
this, &AppearancePageMessageTagTab::slotSelectionChanged); |
|
|
|
slotUpdateTagSettingWidgets(-1); |
|
//Needed since the previous function doesn't affect add button |
|
mTagAddButton->setEnabled(false); |
|
|
|
// Save the original list |
|
mOriginalMsgTagList.clear(); |
|
for (const MailCommon::TagPtr &tag : qAsConst(msgTagList)) { |
|
mOriginalMsgTagList.append(MailCommon::TagPtr(new MailCommon::Tag(*tag))); |
|
} |
|
} |
|
|
|
void AppearancePage::MessageTagTab::save() |
|
{ |
|
const int currentRow = mTagListBox->currentRow(); |
|
if (currentRow < 0) { |
|
return; |
|
} |
|
|
|
const int count = mTagListBox->count(); |
|
if (!count) { |
|
return; |
|
} |
|
|
|
QListWidgetItem *item = mTagListBox->currentItem(); |
|
if (!item) { |
|
return; |
|
} |
|
slotRecordTagSettings(currentRow); |
|
const int numberOfMsgTagList = count; |
|
for (int i = 0; i < numberOfMsgTagList; ++i) { |
|
auto *tagItem = static_cast<TagListWidgetItem *>(mTagListBox->item(i)); |
|
if ((i >= mOriginalMsgTagList.count()) || *(tagItem->kmailTag()) != *(mOriginalMsgTagList[i])) { |
|
MailCommon::Tag::Ptr tag = tagItem->kmailTag(); |
|
tag->priority = i; |
|
Akonadi::Tag akonadiTag = tag->saveToAkonadi(); |
|
if ((*tag).id() > 0) { |
|
akonadiTag.setId((*tag).id()); |
|
} |
|
if (akonadiTag.isValid()) { |
|
new Akonadi::TagModifyJob(akonadiTag); |
|
} else { |
|
new Akonadi::TagCreateJob(akonadiTag); |
|
} |
|
} |
|
} |
|
}
|
|
|