Astyle kdelibs
[kdepim.git] / kmail / configuredialog / configureappearancepage.cpp
blob71baf38478fc3f6b63803bf7d3da61dbd3924970
1 /*
2 Copyright (c) 2013, 2014 Montel Laurent <montel@kde.org>
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #include "configureappearancepage.h"
19 #include "pimcommon/widgets/configureimmutablewidgetutils.h"
20 using namespace PimCommon::ConfigureImmutableWidgetUtils;
21 #include "configuredialog/colorlistbox.h"
22 #include "messagelist/utils/aggregationcombobox.h"
23 #include "messagelist/utils/aggregationconfigbutton.h"
24 #include "messagelist/utils/themecombobox.h"
25 #include "messagelist/utils/themeconfigbutton.h"
26 #include "mailcommon/tag/tagwidget.h"
27 #include "mailcommon/tag/tag.h"
28 #include "kmkernel.h"
29 #include "util.h"
30 #include "foldertreewidget.h"
32 #include "kmmainwidget.h"
34 #include "mailcommon/mailcommonsettings_base.h"
36 #include "messageviewer/widgets/configurewidget.h"
37 #include "messageviewer/settings/globalsettings.h"
39 #include "messagelist/core/settings.h"
40 #include "messagelist/messagelistutil.h"
41 #include "messagecore/settings/globalsettings.h"
42 #include "settings/globalsettings.h"
44 #include "mailcommon/util/mailutil.h"
46 #include <AkonadiCore/Tag>
47 #include <AkonadiCore/TagFetchJob>
48 #include <AkonadiCore/TagFetchScope>
49 #include <AkonadiCore/TagDeleteJob>
50 #include <AkonadiCore/TagCreateJob>
51 #include <AkonadiCore/TagAttribute>
52 #include <AkonadiCore/TagModifyJob>
54 #include <KIconButton>
55 #include <KButtonGroup>
56 #include <KLocalizedString>
57 #include <KColorScheme>
58 #include <KSeparator>
59 #include <KFontChooser>
60 #include <QHBoxLayout>
61 #include <KMessageBox>
62 #include <KKeySequenceWidget>
63 #include <KLineEdit>
64 #include <QDialog>
65 #include <QIcon>
66 #include <QDebug>
68 #include <kmime/kmime_dateformatter.h>
69 using KMime::DateFormatter;
71 #include <QWhatsThis>
72 #include <QButtonGroup>
73 #include <QSpinBox>
74 #include <QLabel>
75 #include <QFontDatabase>
76 using namespace MailCommon;
78 QString AppearancePage::helpAnchor() const
80 return QString::fromLatin1("configure-appearance");
83 AppearancePage::AppearancePage(QWidget *parent)
84 : ConfigModuleWithTabs(parent)
87 // "Fonts" tab:
89 mFontsTab = new FontsTab();
90 addTab(mFontsTab, i18n("Fonts"));
93 // "Colors" tab:
95 mColorsTab = new ColorsTab();
96 addTab(mColorsTab, i18n("Colors"));
99 // "Layout" tab:
101 mLayoutTab = new LayoutTab();
102 addTab(mLayoutTab, i18n("Layout"));
105 // "Headers" tab:
107 mHeadersTab = new HeadersTab();
108 addTab(mHeadersTab, i18n("Message List"));
111 // "Reader window" tab:
113 mReaderTab = new ReaderTab();
114 addTab(mReaderTab, i18n("Message Window"));
115 addConfig(MessageViewer::GlobalSettings::self(), mReaderTab);
118 // "System Tray" tab:
120 mSystemTrayTab = new SystemTrayTab();
121 addTab(mSystemTrayTab, i18n("System Tray"));
124 // "Message Tag" tab:
126 mMessageTagTab = new MessageTagTab();
127 addTab(mMessageTagTab, i18n("Message Tags"));
130 QString AppearancePage::FontsTab::helpAnchor() const
132 return QString::fromLatin1("configure-appearance-fonts");
135 static const struct {
136 const char *configName;
137 const char *displayName;
138 bool enableFamilyAndSize;
139 bool onlyFixed;
140 } fontNames[] = {
141 { "body-font", I18N_NOOP("Message Body"), true, false },
142 { "MessageListFont", I18N_NOOP("Message List"), true, false },
143 { "UnreadMessageFont", I18N_NOOP("Message List - Unread Messages"), true, false },
144 { "ImportantMessageFont", I18N_NOOP("Message List - Important Messages"), true, false },
145 { "TodoMessageFont", I18N_NOOP("Message List - Action Item Messages"), true, false },
146 { "folder-font", I18N_NOOP("Folder List"), true, false },
147 { "quote1-font", I18N_NOOP("Quoted Text - First Level"), false, false },
148 { "quote2-font", I18N_NOOP("Quoted Text - Second Level"), false, false },
149 { "quote3-font", I18N_NOOP("Quoted Text - Third Level"), false, false },
150 { "fixed-font", I18N_NOOP("Fixed Width Font"), true, true },
151 { "composer-font", I18N_NOOP("Composer"), true, false },
152 { "print-font", I18N_NOOP("Printing Output"), true, false },
154 static const int numFontNames = sizeof fontNames / sizeof * fontNames;
156 AppearancePageFontsTab::AppearancePageFontsTab(QWidget *parent)
157 : ConfigModuleTab(parent), mActiveFontIndex(-1)
159 assert(numFontNames == sizeof mFont / sizeof * mFont);
161 // "Use custom fonts" checkbox, followed by <hr>
162 QVBoxLayout *vlay = new QVBoxLayout(this);
163 //TODO PORT QT5 vlay->setSpacing( QDialog::spacingHint() );
164 //TODO PORT QT5 vlay->setMargin( QDialog::marginHint() );
165 mCustomFontCheck = new QCheckBox(i18n("&Use custom fonts"), this);
166 vlay->addWidget(mCustomFontCheck);
167 vlay->addWidget(new KSeparator(Qt::Horizontal, this));
168 connect(mCustomFontCheck, SIGNAL(stateChanged(int)),
169 this, SLOT(slotEmitChanged()));
171 // "font location" combo box and label:
172 QHBoxLayout *hlay = new QHBoxLayout(); // inherites spacing
173 vlay->addLayout(hlay);
174 mFontLocationCombo = new KComboBox(this);
175 mFontLocationCombo->setEditable(false);
176 mFontLocationCombo->setEnabled(false); // !mCustomFontCheck->isChecked()
178 QStringList fontDescriptions;
179 for (int i = 0 ; i < numFontNames ; ++i) {
180 fontDescriptions << i18n(fontNames[i].displayName);
182 mFontLocationCombo->addItems(fontDescriptions);
184 QLabel *label = new QLabel(i18n("Apply &to:"), this);
185 label->setBuddy(mFontLocationCombo);
186 label->setEnabled(false); // since !mCustomFontCheck->isChecked()
187 hlay->addWidget(label);
189 hlay->addWidget(mFontLocationCombo);
190 hlay->addStretch(10);
191 //TODO PORT QT5 vlay->addSpacing( QDialog::spacingHint() );
192 mFontChooser = new KFontChooser(this, KFontChooser::DisplayFrame,
193 QStringList(), 4);
194 mFontChooser->setEnabled(false); // since !mCustomFontCheck->isChecked()
195 vlay->addWidget(mFontChooser);
196 connect(mFontChooser, SIGNAL(fontSelected(QFont)),
197 this, SLOT(slotEmitChanged()));
199 // {en,dis}able widgets depending on the state of mCustomFontCheck:
200 connect(mCustomFontCheck, SIGNAL(toggled(bool)),
201 label, SLOT(setEnabled(bool)));
202 connect(mCustomFontCheck, SIGNAL(toggled(bool)),
203 mFontLocationCombo, SLOT(setEnabled(bool)));
204 connect(mCustomFontCheck, SIGNAL(toggled(bool)),
205 mFontChooser, SLOT(setEnabled(bool)));
206 // load the right font settings into mFontChooser:
207 connect(mFontLocationCombo, SIGNAL(activated(int)),
208 this, SLOT(slotFontSelectorChanged(int)));
211 void AppearancePage::FontsTab::slotFontSelectorChanged(int index)
213 qDebug() << "slotFontSelectorChanged() called";
214 if (index < 0 || index >= mFontLocationCombo->count()) {
215 return; // Should never happen, but it is better to check.
218 // Save current fontselector setting before we install the new:
219 if (mActiveFontIndex == 0) {
220 mFont[0] = mFontChooser->font();
221 // hardcode the family and size of "message body" dependant fonts:
222 for (int i = 0 ; i < numFontNames ; ++i)
223 if (!fontNames[i].enableFamilyAndSize) {
224 // ### shall we copy the font and set the save and re-set
225 // {regular,italic,bold,bold italic} property or should we
226 // copy only family and pointSize?
227 mFont[i].setFamily(mFont[0].family());
228 mFont[i].setPointSize/*Float?*/(mFont[0].pointSize/*Float?*/());
230 } else if (mActiveFontIndex > 0) {
231 mFont[ mActiveFontIndex ] = mFontChooser->font();
233 mActiveFontIndex = index;
235 // Disonnect so the "Apply" button is not activated by the change
236 disconnect(mFontChooser, SIGNAL(fontSelected(QFont)),
237 this, SLOT(slotEmitChanged()));
239 // Display the new setting:
240 mFontChooser->setFont(mFont[index], fontNames[index].onlyFixed);
242 connect(mFontChooser, SIGNAL(fontSelected(QFont)),
243 this, SLOT(slotEmitChanged()));
245 // Disable Family and Size list if we have selected a quote font:
246 mFontChooser->enableColumn(KFontChooser::FamilyList | KFontChooser::SizeList,
247 fontNames[ index ].enableFamilyAndSize);
250 void AppearancePage::FontsTab::doLoadOther()
252 if (KMKernel::self()) {
253 KConfigGroup fonts(KMKernel::self()->config(), "Fonts");
254 KConfigGroup messagelistFont(KMKernel::self()->config(), "MessageListView::Fonts");
256 mFont[0] = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
257 QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
259 for (int i = 0 ; i < numFontNames ; ++i) {
260 const QString configName = QLatin1String(fontNames[i].configName);
261 if (configName == QLatin1String("MessageListFont") ||
262 configName == QLatin1String("UnreadMessageFont") ||
263 configName == QLatin1String("ImportantMessageFont") ||
264 configName == QLatin1String("TodoMessageFont")) {
265 mFont[i] = messagelistFont.readEntry(configName,
266 (fontNames[i].onlyFixed) ? fixedFont : mFont[0]);
267 } else {
268 mFont[i] = fonts.readEntry(configName,
269 (fontNames[i].onlyFixed) ? fixedFont : mFont[0]);
272 mCustomFontCheck->setChecked(!MessageCore::GlobalSettings::self()->useDefaultFonts());
273 mFontLocationCombo->setCurrentIndex(0);
274 slotFontSelectorChanged(0);
275 } else {
276 setEnabled(false);
280 void AppearancePage::FontsTab::save()
282 if (KMKernel::self()) {
283 KConfigGroup fonts(KMKernel::self()->config(), "Fonts");
284 KConfigGroup messagelistFont(KMKernel::self()->config(), "MessageListView::Fonts");
286 // read the current font (might have been modified)
287 if (mActiveFontIndex >= 0) {
288 mFont[ mActiveFontIndex ] = mFontChooser->font();
291 const bool customFonts = mCustomFontCheck->isChecked();
292 MessageCore::GlobalSettings::self()->setUseDefaultFonts(!customFonts);
294 for (int i = 0 ; i < numFontNames ; ++i) {
295 const QString configName = QLatin1String(fontNames[i].configName);
296 if (configName == QLatin1String("MessageListFont") ||
297 configName == QLatin1String("UnreadMessageFont") ||
298 configName == QLatin1String("ImportantMessageFont") ||
299 configName == QLatin1String("TodoMessageFont")) {
300 if (customFonts || messagelistFont.hasKey(configName)) {
301 // Don't write font info when we use default fonts, but write
302 // if it's already there:
303 messagelistFont.writeEntry(configName, mFont[i]);
305 } else {
306 if (customFonts || fonts.hasKey(configName))
307 // Don't write font info when we use default fonts, but write
308 // if it's already there:
310 fonts.writeEntry(configName, mFont[i]);
317 void AppearancePage::FontsTab::doResetToDefaultsOther()
319 mCustomFontCheck->setChecked(false);
322 QString AppearancePage::ColorsTab::helpAnchor() const
324 return QString::fromLatin1("configure-appearance-colors");
327 static const struct {
328 const char *configName;
329 const char *displayName;
330 } colorNames[] = { // adjust doLoadOther if you change this:
331 { "QuotedText1", I18N_NOOP("Quoted Text - First Level") },
332 { "QuotedText2", I18N_NOOP("Quoted Text - Second Level") },
333 { "QuotedText3", I18N_NOOP("Quoted Text - Third Level") },
334 { "LinkColor", I18N_NOOP("Link") },
335 { "FollowedColor", I18N_NOOP("Followed Link") },
336 { "MisspelledColor", I18N_NOOP("Misspelled Words") },
337 { "UnreadMessageColor", I18N_NOOP("Unread Message") },
338 { "ImportantMessageColor", I18N_NOOP("Important Message") },
339 { "TodoMessageColor", I18N_NOOP("Action Item Message") },
340 { "PGPMessageEncr", I18N_NOOP("OpenPGP Message - Encrypted") },
341 { "PGPMessageOkKeyOk", I18N_NOOP("OpenPGP Message - Valid Signature with Trusted Key") },
342 { "PGPMessageOkKeyBad", I18N_NOOP("OpenPGP Message - Valid Signature with Untrusted Key") },
343 { "PGPMessageWarn", I18N_NOOP("OpenPGP Message - Unchecked Signature") },
344 { "PGPMessageErr", I18N_NOOP("OpenPGP Message - Bad Signature") },
345 { "HTMLWarningColor", I18N_NOOP("Border Around Warning Prepending HTML Messages") },
346 { "CloseToQuotaColor", I18N_NOOP("Folder Name and Size When Close to Quota") },
347 { "ColorbarBackgroundPlain", I18N_NOOP("HTML Status Bar Background - No HTML Message") },
348 { "ColorbarForegroundPlain", I18N_NOOP("HTML Status Bar Foreground - No HTML Message") },
349 { "ColorbarBackgroundHTML", I18N_NOOP("HTML Status Bar Background - HTML Message") },
350 { "ColorbarForegroundHTML", I18N_NOOP("HTML Status Bar Foreground - HTML Message") },
351 { "BrokenAccountColor", I18N_NOOP("Broken Account - Folder Text Color") },
352 { "BackgroundColor", I18N_NOOP("Background Color") },
354 static const int numColorNames = sizeof colorNames / sizeof * colorNames;
356 AppearancePageColorsTab::AppearancePageColorsTab(QWidget *parent)
357 : ConfigModuleTab(parent)
359 // "use custom colors" check box
360 QVBoxLayout *vlay = new QVBoxLayout(this);
361 //TODO PORT QT5 vlay->setSpacing( QDialog::spacingHint() );
362 //TODO PORT QT5 vlay->setMargin( QDialog::marginHint() );
363 mCustomColorCheck = new QCheckBox(i18n("&Use custom colors"), this);
364 vlay->addWidget(mCustomColorCheck);
365 connect(mCustomColorCheck, SIGNAL(stateChanged(int)),
366 this, SLOT(slotEmitChanged()));
368 // color list box:
369 mColorList = new ColorListBox(this);
370 mColorList->setEnabled(false); // since !mCustomColorCheck->isChecked()
371 for (int i = 0 ; i < numColorNames ; ++i) {
372 mColorList->addColor(i18n(colorNames[i].displayName));
374 vlay->addWidget(mColorList, 1);
376 // "recycle colors" check box:
377 mRecycleColorCheck =
378 new QCheckBox(i18n("Recycle colors on deep &quoting"), this);
379 mRecycleColorCheck->setEnabled(false);
380 vlay->addWidget(mRecycleColorCheck);
381 connect(mRecycleColorCheck, SIGNAL(stateChanged(int)),
382 this, SLOT(slotEmitChanged()));
384 // close to quota threshold
385 QHBoxLayout *hbox = new QHBoxLayout();
386 vlay->addLayout(hbox);
387 QLabel *l = new QLabel(i18n("Close to quota threshold:"), this);
388 hbox->addWidget(l);
389 mCloseToQuotaThreshold = new QSpinBox(this);
390 mCloseToQuotaThreshold->setRange(0, 100);
391 mCloseToQuotaThreshold->setSingleStep(1);
392 connect(mCloseToQuotaThreshold, SIGNAL(valueChanged(int)),
393 this, SLOT(slotEmitChanged()));
394 mCloseToQuotaThreshold->setSuffix(i18n("%"));
396 hbox->addWidget(mCloseToQuotaThreshold);
397 hbox->addWidget(new QWidget(this), 2);
399 // {en,dir}able widgets depending on the state of mCustomColorCheck:
400 connect(mCustomColorCheck, SIGNAL(toggled(bool)),
401 mColorList, SLOT(setEnabled(bool)));
402 connect(mCustomColorCheck, SIGNAL(toggled(bool)),
403 mRecycleColorCheck, SLOT(setEnabled(bool)));
404 connect(mCustomColorCheck, SIGNAL(stateChanged(int)),
405 this, SLOT(slotEmitChanged()));
406 connect(mColorList, SIGNAL(changed()),
407 this, SLOT(slotEmitChanged()));
410 void AppearancePage::ColorsTab::doLoadOther()
412 mCustomColorCheck->setChecked(!MessageCore::GlobalSettings::self()->useDefaultColors());
413 mRecycleColorCheck->setChecked(MessageViewer::GlobalSettings::self()->recycleQuoteColors());
414 mCloseToQuotaThreshold->setValue(GlobalSettings::self()->closeToQuotaThreshold());
415 loadColor(true);
418 void AppearancePage::ColorsTab::loadColor(bool loadFromConfig)
420 if (KMKernel::self()) {
421 KColorScheme scheme(QPalette::Active, KColorScheme::View);
423 KConfigGroup reader(KMKernel::self()->config(), "Reader");
425 KConfigGroup messageListView(KMKernel::self()->config(), "MessageListView::Colors");
427 KConfigGroup collectionFolderView(KMKernel::self()->config(), "CollectionFolderView");
429 static const QColor defaultColor[ numColorNames ] = {
430 KMail::Util::quoteL1Color(),
431 KMail::Util::quoteL2Color(),
432 KMail::Util::quoteL3Color(),
433 scheme.foreground(KColorScheme::LinkText).color(), // link
434 scheme.foreground(KColorScheme::VisitedText).color(), // visited link
435 scheme.foreground(KColorScheme::NegativeText).color(), // misspelled words
436 MessageList::Util::unreadDefaultMessageColor(), // unread mgs
437 MessageList::Util::importantDefaultMessageColor(), // important msg
438 MessageList::Util::todoDefaultMessageColor(), // action item mgs
439 QColor(0x00, 0x80, 0xFF), // pgp encrypted
440 scheme.background(KColorScheme::PositiveBackground).color(), // pgp ok, trusted key
441 QColor(0xFF, 0xFF, 0x40), // pgp ok, untrusted key
442 QColor(0xFF, 0xFF, 0x40), // pgp unchk
443 Qt::red, // pgp bad
444 QColor(0xFF, 0x40, 0x40), // warning text color
445 MailCommon::Util::defaultQuotaColor(), // close to quota
446 Qt::lightGray, // colorbar plain bg
447 Qt::black, // colorbar plain fg
448 Qt::black, // colorbar html bg
449 Qt::white, // colorbar html fg
450 scheme.foreground(KColorScheme::NegativeText).color(), //Broken Account Color
451 scheme.background().color() // reader background color
454 for (int i = 0 ; i < numColorNames ; ++i) {
455 if (loadFromConfig) {
456 const QString configName = QLatin1String(colorNames[i].configName);
457 if (configName == QLatin1String("UnreadMessageColor") ||
458 configName == QLatin1String("ImportantMessageColor") ||
459 configName == QLatin1String("TodoMessageColor")) {
460 mColorList->setColorSilently(i, messageListView.readEntry(configName, defaultColor[i]));
461 } else if (configName == QLatin1String("BrokenAccountColor")) {
462 mColorList->setColorSilently(i, collectionFolderView.readEntry(configName, defaultColor[i]));
463 } else {
464 mColorList->setColorSilently(i, reader.readEntry(configName, defaultColor[i]));
466 } else {
467 mColorList->setColorSilently(i, defaultColor[i]);
470 } else {
471 setEnabled(false);
475 void AppearancePage::ColorsTab::doResetToDefaultsOther()
477 mCustomColorCheck->setChecked(false);
478 mRecycleColorCheck->setChecked(false);
479 mCloseToQuotaThreshold->setValue(80);
480 loadColor(false);
483 void AppearancePage::ColorsTab::save()
485 if (!KMKernel::self()) {
486 return;
488 KConfigGroup reader(KMKernel::self()->config(), "Reader");
489 KConfigGroup messageListView(KMKernel::self()->config(), "MessageListView::Colors");
490 KConfigGroup collectionFolderView(KMKernel::self()->config(), "CollectionFolderView");
491 bool customColors = mCustomColorCheck->isChecked();
492 MessageCore::GlobalSettings::self()->setUseDefaultColors(!customColors);
494 KColorScheme scheme(QPalette::Active, KColorScheme::View);
496 for (int i = 0 ; i < numColorNames ; ++i) {
497 // Don't write color info when we use default colors, but write
498 // if it's already there:
499 const QString configName = QLatin1String(colorNames[i].configName);
500 if (configName == QLatin1String("UnreadMessageColor") ||
501 configName == QLatin1String("ImportantMessageColor") ||
502 configName == QLatin1String("TodoMessageColor")) {
503 if (customColors || messageListView.hasKey(configName)) {
504 messageListView.writeEntry(configName, mColorList->color(i));
507 } else if (configName == QLatin1String("BrokenAccountColor")) {
508 if (customColors || collectionFolderView.hasKey(configName)) {
509 collectionFolderView.writeEntry(configName, mColorList->color(i));
511 } else if (configName == QLatin1String("BackgroundColor")) {
512 if (customColors && (mColorList->color(i) != scheme.background().color())) {
513 reader.writeEntry(configName, mColorList->color(i));
515 } else {
516 if (customColors || reader.hasKey(configName)) {
517 reader.writeEntry(configName, mColorList->color(i));
521 MessageViewer::GlobalSettings::self()->setRecycleQuoteColors(mRecycleColorCheck->isChecked());
522 GlobalSettings::self()->setCloseToQuotaThreshold(mCloseToQuotaThreshold->value());
525 QString AppearancePage::LayoutTab::helpAnchor() const
527 return QString::fromLatin1("configure-appearance-layout");
530 AppearancePageLayoutTab::AppearancePageLayoutTab(QWidget *parent)
531 : ConfigModuleTab(parent)
533 QVBoxLayout *vlay = new QVBoxLayout(this);
534 //TODO PORT QT5 vlay->setSpacing( QDialog::spacingHint() );
535 //TODO PORT QT5 vlay->setMargin( QDialog::marginHint() );
537 // "folder list" radio buttons:
538 populateButtonGroup(mFolderListGroupBox = new QGroupBox(this),
539 mFolderListGroup = new QButtonGroup(this),
540 Qt::Vertical, GlobalSettings::self()->folderListItem());
541 vlay->addWidget(mFolderListGroupBox);
542 connect(mFolderListGroup, SIGNAL(buttonClicked(int)),
543 this, SLOT(slotEmitChanged()));
545 QHBoxLayout *folderCBHLayout = new QHBoxLayout();
546 mFolderQuickSearchCB = new QCheckBox(i18n("Show folder quick search field"), this);
547 connect(mFolderQuickSearchCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()));
548 folderCBHLayout->addWidget(mFolderQuickSearchCB);
549 vlay->addLayout(folderCBHLayout);
550 //TODO PORT QT5 vlay->addSpacing( QDialog::spacingHint() ); // space before next box
552 // "favorite folders view mode" radio buttons:
553 mFavoriteFoldersViewGroupBox = new QGroupBox(this);
554 mFavoriteFoldersViewGroupBox->setTitle(i18n("Show Favorite Folders View"));
555 mFavoriteFoldersViewGroupBox->setLayout(new QVBoxLayout());
556 mFavoriteFoldersViewGroup = new QButtonGroup(this);
557 connect(mFavoriteFoldersViewGroup, SIGNAL(buttonClicked(int)),
558 this, SLOT(slotEmitChanged()));
560 QRadioButton *favoriteFoldersViewHiddenRadio = new QRadioButton(i18n("Never"), mFavoriteFoldersViewGroupBox);
561 mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewHiddenRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode));
562 mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewHiddenRadio);
564 QRadioButton *favoriteFoldersViewIconsRadio = new QRadioButton(i18n("As icons"), mFavoriteFoldersViewGroupBox);
565 mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewIconsRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode));
566 mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewIconsRadio);
568 QRadioButton *favoriteFoldersViewListRadio = new QRadioButton(i18n("As list"), mFavoriteFoldersViewGroupBox);
569 mFavoriteFoldersViewGroup->addButton(favoriteFoldersViewListRadio, static_cast<int>(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode));
570 mFavoriteFoldersViewGroupBox->layout()->addWidget(favoriteFoldersViewListRadio);
572 vlay->addWidget(mFavoriteFoldersViewGroupBox);
574 // "folder tooltips" radio buttons:
575 mFolderToolTipsGroupBox = new QGroupBox(this);
576 mFolderToolTipsGroupBox->setTitle(i18n("Folder Tooltips"));
577 mFolderToolTipsGroupBox->setLayout(new QVBoxLayout());
578 //TODO PORT QT5 mFolderToolTipsGroupBox->layout()->setSpacing( QDialog::spacingHint() );
579 mFolderToolTipsGroup = new QButtonGroup(this);
580 connect(mFolderToolTipsGroup, SIGNAL(buttonClicked(int)),
581 this, SLOT(slotEmitChanged()));
583 QRadioButton *folderToolTipsAlwaysRadio = new QRadioButton(i18n("Always"), mFolderToolTipsGroupBox);
584 mFolderToolTipsGroup->addButton(folderToolTipsAlwaysRadio, static_cast< int >(FolderTreeWidget::DisplayAlways));
585 mFolderToolTipsGroupBox->layout()->addWidget(folderToolTipsAlwaysRadio);
587 QRadioButton *folderToolTipsNeverRadio = new QRadioButton(i18n("Never"), mFolderToolTipsGroupBox);
588 mFolderToolTipsGroup->addButton(folderToolTipsNeverRadio, static_cast< int >(FolderTreeWidget::DisplayNever));
589 mFolderToolTipsGroupBox->layout()->addWidget(folderToolTipsNeverRadio);
591 vlay->addWidget(mFolderToolTipsGroupBox);
593 // "show reader window" radio buttons:
594 populateButtonGroup(mReaderWindowModeGroupBox = new QGroupBox(this),
595 mReaderWindowModeGroup = new QButtonGroup(this),
596 Qt::Vertical, GlobalSettings::self()->readerWindowModeItem());
597 vlay->addWidget(mReaderWindowModeGroupBox);
598 connect(mReaderWindowModeGroup, SIGNAL(buttonClicked(int)),
599 this, SLOT(slotEmitChanged()));
601 vlay->addStretch(10); // spacer
604 void AppearancePage::LayoutTab::doLoadOther()
606 loadWidget(mFolderListGroupBox, mFolderListGroup, GlobalSettings::self()->folderListItem());
607 loadWidget(mReaderWindowModeGroupBox, mReaderWindowModeGroup, GlobalSettings::self()->readerWindowModeItem());
608 loadWidget(mFavoriteFoldersViewGroupBox, mFavoriteFoldersViewGroup, MailCommon::MailCommonSettings::self()->favoriteCollectionViewModeItem());
609 loadWidget(mFolderQuickSearchCB, GlobalSettings::self()->enableFolderQuickSearchItem());
610 const int checkedFolderToolTipsPolicy = GlobalSettings::self()->toolTipDisplayPolicy();
611 if (checkedFolderToolTipsPolicy >= 0) {
612 mFolderToolTipsGroup->button(checkedFolderToolTipsPolicy)->setChecked(true);
616 void AppearancePage::LayoutTab::save()
618 saveButtonGroup(mFolderListGroup, GlobalSettings::self()->folderListItem());
619 saveButtonGroup(mReaderWindowModeGroup, GlobalSettings::self()->readerWindowModeItem());
620 saveButtonGroup(mFavoriteFoldersViewGroup, MailCommon::MailCommonSettings::self()->favoriteCollectionViewModeItem());
621 saveCheckBox(mFolderQuickSearchCB, GlobalSettings::self()->enableFolderQuickSearchItem());
622 GlobalSettings::self()->setToolTipDisplayPolicy(mFolderToolTipsGroup->checkedId());
626 // Appearance Message List
629 QString AppearancePage::HeadersTab::helpAnchor() const
631 return QString::fromLatin1("configure-appearance-headers");
634 static const struct {
635 const char *displayName;
636 DateFormatter::FormatType dateDisplay;
637 } dateDisplayConfig[] = {
638 { I18N_NOOP("Sta&ndard format (%1)"), KMime::DateFormatter::CTime },
639 { I18N_NOOP("Locali&zed format (%1)"), KMime::DateFormatter::Localized },
640 { I18N_NOOP("Smart for&mat (%1)"), KMime::DateFormatter::Fancy },
641 { I18N_NOOP("C&ustom format:"), KMime::DateFormatter::Custom }
643 static const int numDateDisplayConfig =
644 sizeof dateDisplayConfig / sizeof * dateDisplayConfig;
646 AppearancePageHeadersTab::AppearancePageHeadersTab(QWidget *parent)
647 : ConfigModuleTab(parent),
648 mCustomDateFormatEdit(0)
650 QVBoxLayout *vlay = new QVBoxLayout(this);
651 //TODO PORT QT5 vlay->setSpacing( QDialog::spacingHint() );
652 //TODO PORT QT5 vlay->setMargin( QDialog::marginHint() );
654 // "General Options" group:
655 QGroupBox *group = new QGroupBox(i18nc("General options for the message list.", "General"), this);
656 //TODO PORT QT5 // group->layout()->setSpacing( QDialog::spacingHint() );
657 QVBoxLayout *gvlay = new QVBoxLayout(group);
658 //TODO PORT QT5 gvlay->setSpacing( QDialog::spacingHint() );
660 mDisplayMessageToolTips = new QCheckBox(
661 MessageList::Core::Settings::self()->messageToolTipEnabledItem()->label(), group);
662 gvlay->addWidget(mDisplayMessageToolTips);
664 connect(mDisplayMessageToolTips, SIGNAL(stateChanged(int)),
665 this, SLOT(slotEmitChanged()));
667 mHideTabBarWithSingleTab = new QCheckBox(
668 MessageList::Core::Settings::self()->autoHideTabBarWithSingleTabItem()->label(), group);
669 gvlay->addWidget(mHideTabBarWithSingleTab);
671 connect(mHideTabBarWithSingleTab, SIGNAL(stateChanged(int)),
672 this, SLOT(slotEmitChanged()));
674 mTabsHaveCloseButton = new QCheckBox(
675 MessageList::Core::Settings::self()->tabsHaveCloseButtonItem()->label(), group);
676 gvlay->addWidget(mTabsHaveCloseButton);
678 connect(mTabsHaveCloseButton, SIGNAL(stateChanged(int)),
679 this, SLOT(slotEmitChanged()));
681 // "Aggregation"
682 using MessageList::Utils::AggregationComboBox;
683 mAggregationComboBox = new AggregationComboBox(group);
685 QLabel *aggregationLabel = new QLabel(i18n("Default aggregation:"), group);
686 aggregationLabel->setBuddy(mAggregationComboBox);
688 using MessageList::Utils::AggregationConfigButton;
689 AggregationConfigButton *aggregationConfigButton = new AggregationConfigButton(group, mAggregationComboBox);
691 QHBoxLayout *aggregationLayout = new QHBoxLayout();
692 aggregationLayout->addWidget(aggregationLabel, 1);
693 aggregationLayout->addWidget(mAggregationComboBox, 1);
694 aggregationLayout->addWidget(aggregationConfigButton, 0);
695 gvlay->addLayout(aggregationLayout);
697 connect(aggregationConfigButton, SIGNAL(configureDialogCompleted()),
698 this, SLOT(slotSelectDefaultAggregation()));
699 connect(mAggregationComboBox, SIGNAL(activated(int)),
700 this, SLOT(slotEmitChanged()));
702 // "Theme"
703 using MessageList::Utils::ThemeComboBox;
704 mThemeComboBox = new ThemeComboBox(group);
706 QLabel *themeLabel = new QLabel(i18n("Default theme:"), group);
707 themeLabel->setBuddy(mThemeComboBox);
709 using MessageList::Utils::ThemeConfigButton;
710 ThemeConfigButton *themeConfigButton = new ThemeConfigButton(group, mThemeComboBox);
712 QHBoxLayout *themeLayout = new QHBoxLayout();
713 themeLayout->addWidget(themeLabel, 1);
714 themeLayout->addWidget(mThemeComboBox, 1);
715 themeLayout->addWidget(themeConfigButton, 0);
716 gvlay->addLayout(themeLayout);
718 connect(themeConfigButton, SIGNAL(configureDialogCompleted()),
719 this, SLOT(slotSelectDefaultTheme()));
720 connect(mThemeComboBox, SIGNAL(activated(int)),
721 this, SLOT(slotEmitChanged()));
723 vlay->addWidget(group);
725 // "Date Display" group:
726 mDateDisplay = new KButtonGroup(this);
727 mDateDisplay->setTitle(i18n("Date Display"));
728 gvlay = new QVBoxLayout(mDateDisplay);
729 //TODO PORT QT5 gvlay->setSpacing( QDialog::spacingHint() );
731 for (int i = 0 ; i < numDateDisplayConfig ; ++i) {
732 const char *label = dateDisplayConfig[i].displayName;
733 QString buttonLabel;
734 if (QString::fromLatin1(label).contains(QLatin1String("%1"))) {
735 buttonLabel = i18n(label, DateFormatter::formatCurrentDate(dateDisplayConfig[i].dateDisplay));
736 } else {
737 buttonLabel = i18n(label);
739 QRadioButton *radio = new QRadioButton(buttonLabel, mDateDisplay);
740 gvlay->addWidget(radio);
742 if (dateDisplayConfig[i].dateDisplay == DateFormatter::Custom) {
743 QWidget *hbox = new QWidget(mDateDisplay);
744 QHBoxLayout *hboxHBoxLayout = new QHBoxLayout(hbox);
745 hboxHBoxLayout->setMargin(0);
746 //TODO PORT QT5 hboxHBoxLayout->setSpacing( QDialog::spacingHint() );
748 mCustomDateFormatEdit = new KLineEdit(hbox);
749 hboxHBoxLayout->addWidget(mCustomDateFormatEdit);
750 mCustomDateFormatEdit->setEnabled(false);
751 hboxHBoxLayout->setStretchFactor(mCustomDateFormatEdit, 1);
753 connect(radio, SIGNAL(toggled(bool)),
754 mCustomDateFormatEdit, SLOT(setEnabled(bool)));
755 connect(mCustomDateFormatEdit, SIGNAL(textChanged(QString)),
756 this, SLOT(slotEmitChanged()));
758 QLabel *formatHelp = new QLabel(
759 i18n("<qt><a href=\"whatsthis1\">Custom format information...</a></qt>"), hbox);
760 formatHelp->setContextMenuPolicy(Qt::NoContextMenu);
761 connect(formatHelp, SIGNAL(linkActivated(QString)),
762 SLOT(slotLinkClicked(QString)));
763 hboxHBoxLayout->addWidget(formatHelp);
765 mCustomDateWhatsThis =
766 i18n("<qt><p><strong>These expressions may be used for the date:"
767 "</strong></p>"
768 "<ul>"
769 "<li>d - the day as a number without a leading zero (1-31)</li>"
770 "<li>dd - the day as a number with a leading zero (01-31)</li>"
771 "<li>ddd - the abbreviated day name (Mon - Sun)</li>"
772 "<li>dddd - the long day name (Monday - Sunday)</li>"
773 "<li>M - the month as a number without a leading zero (1-12)</li>"
774 "<li>MM - the month as a number with a leading zero (01-12)</li>"
775 "<li>MMM - the abbreviated month name (Jan - Dec)</li>"
776 "<li>MMMM - the long month name (January - December)</li>"
777 "<li>yy - the year as a two digit number (00-99)</li>"
778 "<li>yyyy - the year as a four digit number (0000-9999)</li>"
779 "</ul>"
780 "<p><strong>These expressions may be used for the time:"
781 "</strong></p> "
782 "<ul>"
783 "<li>h - the hour without a leading zero (0-23 or 1-12 if AM/PM display)</li>"
784 "<li>hh - the hour with a leading zero (00-23 or 01-12 if AM/PM display)</li>"
785 "<li>m - the minutes without a leading zero (0-59)</li>"
786 "<li>mm - the minutes with a leading zero (00-59)</li>"
787 "<li>s - the seconds without a leading zero (0-59)</li>"
788 "<li>ss - the seconds with a leading zero (00-59)</li>"
789 "<li>z - the milliseconds without leading zeroes (0-999)</li>"
790 "<li>zzz - the milliseconds with leading zeroes (000-999)</li>"
791 "<li>AP - switch to AM/PM display. AP will be replaced by either \"AM\" or \"PM\".</li>"
792 "<li>ap - switch to AM/PM display. ap will be replaced by either \"am\" or \"pm\".</li>"
793 "<li>Z - time zone in numeric form (-0500)</li>"
794 "</ul>"
795 "<p><strong>All other input characters will be ignored."
796 "</strong></p></qt>");
797 mCustomDateFormatEdit->setWhatsThis(mCustomDateWhatsThis);
798 radio->setWhatsThis(mCustomDateWhatsThis);
799 gvlay->addWidget(hbox);
801 } // end for loop populating mDateDisplay
803 vlay->addWidget(mDateDisplay);
804 connect(mDateDisplay, SIGNAL(clicked(int)),
805 this, SLOT(slotEmitChanged()));
807 vlay->addStretch(10); // spacer
810 void AppearancePageHeadersTab::slotLinkClicked(const QString &link)
812 if (link == QLatin1String("whatsthis1")) {
813 QWhatsThis::showText(QCursor::pos(), mCustomDateWhatsThis);
817 void AppearancePage::HeadersTab::slotSelectDefaultAggregation()
819 // Select current default aggregation.
820 mAggregationComboBox->selectDefault();
823 void AppearancePage::HeadersTab::slotSelectDefaultTheme()
825 // Select current default theme.
826 mThemeComboBox->selectDefault();
829 void AppearancePage::HeadersTab::doLoadOther()
831 // "General Options":
832 loadWidget(mDisplayMessageToolTips, MessageList::Core::Settings::self()->messageToolTipEnabledItem());
833 loadWidget(mHideTabBarWithSingleTab, MessageList::Core::Settings::self()->autoHideTabBarWithSingleTabItem());
834 loadWidget(mTabsHaveCloseButton, MessageList::Core::Settings::self()->tabsHaveCloseButtonItem());
836 // "Aggregation":
837 slotSelectDefaultAggregation();
839 // "Theme":
840 slotSelectDefaultTheme();
842 // "Date Display":
843 setDateDisplay(MessageCore::GlobalSettings::self()->dateFormat(),
844 MessageCore::GlobalSettings::self()->customDateFormat());
847 void AppearancePage::HeadersTab::doLoadFromGlobalSettings()
849 loadWidget(mDisplayMessageToolTips, MessageList::Core::Settings::self()->messageToolTipEnabledItem());
850 loadWidget(mHideTabBarWithSingleTab, MessageList::Core::Settings::self()->autoHideTabBarWithSingleTabItem());
851 loadWidget(mTabsHaveCloseButton, MessageList::Core::Settings::self()->tabsHaveCloseButtonItem());
852 // "Aggregation":
853 slotSelectDefaultAggregation();
855 // "Theme":
856 slotSelectDefaultTheme();
858 setDateDisplay(MessageCore::GlobalSettings::self()->dateFormat(),
859 MessageCore::GlobalSettings::self()->customDateFormat());
862 void AppearancePage::HeadersTab::setDateDisplay(int num, const QString &format)
864 DateFormatter::FormatType dateDisplay =
865 static_cast<DateFormatter::FormatType>(num);
867 // special case: needs text for the line edit:
868 if (dateDisplay == DateFormatter::Custom) {
869 mCustomDateFormatEdit->setText(format);
872 for (int i = 0 ; i < numDateDisplayConfig ; ++i)
873 if (dateDisplay == dateDisplayConfig[i].dateDisplay) {
874 mDateDisplay->setSelected(i);
875 return;
877 // fell through since none found:
878 mDateDisplay->setSelected(numDateDisplayConfig - 2); // default
881 void AppearancePage::HeadersTab::save()
883 saveCheckBox(mDisplayMessageToolTips, MessageList::Core::Settings::self()->messageToolTipEnabledItem());
884 saveCheckBox(mHideTabBarWithSingleTab, MessageList::Core::Settings::self()->autoHideTabBarWithSingleTabItem());
885 saveCheckBox(mTabsHaveCloseButton, MessageList::Core::Settings::self()->tabsHaveCloseButtonItem());
887 KMKernel::self()->savePaneSelection();
888 // "Aggregation"
889 mAggregationComboBox->writeDefaultConfig();
891 // "Theme"
892 mThemeComboBox->writeDefaultConfig();
894 const int dateDisplayID = mDateDisplay->selected();
895 // check bounds:
896 if ((dateDisplayID >= 0) && (dateDisplayID < numDateDisplayConfig)) {
897 MessageCore::GlobalSettings::self()->setDateFormat(
898 static_cast<int>(dateDisplayConfig[ dateDisplayID ].dateDisplay));
900 MessageCore::GlobalSettings::self()->setCustomDateFormat(mCustomDateFormatEdit->text());
904 // Message Window
907 QString AppearancePage::ReaderTab::helpAnchor() const
909 return QString::fromLatin1("configure-appearance-reader");
912 AppearancePageReaderTab::AppearancePageReaderTab(QWidget *parent)
913 : ConfigModuleTab(parent)
915 QVBoxLayout *topLayout = new QVBoxLayout(this);
916 //TODO PORT QT5 topLayout->setSpacing( QDialog::spacingHint() );
917 //TODO PORT QT5 topLayout->setMargin( QDialog::marginHint() );
919 // "Close message window after replying or forwarding" check box:
920 populateCheckBox(mCloseAfterReplyOrForwardCheck = new QCheckBox(this),
921 GlobalSettings::self()->closeAfterReplyOrForwardItem());
922 mCloseAfterReplyOrForwardCheck->setToolTip(
923 i18n("Close the standalone message window after replying or forwarding the message"));
924 topLayout->addWidget(mCloseAfterReplyOrForwardCheck);
925 connect(mCloseAfterReplyOrForwardCheck, SIGNAL(stateChanged(int)),
926 this, SLOT(slotEmitChanged()));
928 mViewerSettings = new MessageViewer::ConfigureWidget;
929 connect(mViewerSettings, SIGNAL(settingsChanged()),
930 this, SLOT(slotEmitChanged()));
931 topLayout->addWidget(mViewerSettings);
933 topLayout->addStretch(100); // spacer
936 void AppearancePage::ReaderTab::doResetToDefaultsOther()
940 void AppearancePage::ReaderTab::doLoadOther()
942 loadWidget(mCloseAfterReplyOrForwardCheck, GlobalSettings::self()->closeAfterReplyOrForwardItem());
943 mViewerSettings->readConfig();
946 void AppearancePage::ReaderTab::save()
948 saveCheckBox(mCloseAfterReplyOrForwardCheck, GlobalSettings::self()->closeAfterReplyOrForwardItem());
949 mViewerSettings->writeConfig();
952 QString AppearancePage::SystemTrayTab::helpAnchor() const
954 return QString::fromLatin1("configure-appearance-systemtray");
957 AppearancePageSystemTrayTab::AppearancePageSystemTrayTab(QWidget *parent)
958 : ConfigModuleTab(parent)
960 QVBoxLayout *vlay = new QVBoxLayout(this);
961 //TODO PORT QT5 vlay->setSpacing( QDialog::spacingHint() );
962 //TODO PORT QT5 vlay->setMargin( QDialog::marginHint() );
964 // "Enable system tray applet" check box
965 mSystemTrayCheck = new QCheckBox(i18n("Enable system tray icon"), this);
966 vlay->addWidget(mSystemTrayCheck);
967 connect(mSystemTrayCheck, SIGNAL(stateChanged(int)),
968 this, SLOT(slotEmitChanged()));
970 mSystemTrayShowUnreadMail = new QCheckBox(i18n("Show unread mail in tray icon"), this);
971 vlay->addWidget(mSystemTrayShowUnreadMail);
972 mSystemTrayShowUnreadMail->setEnabled(false);
973 connect(mSystemTrayShowUnreadMail, SIGNAL(stateChanged(int)),
974 this, SLOT(slotEmitChanged()));
975 connect(mSystemTrayCheck, SIGNAL(toggled(bool)),
976 mSystemTrayShowUnreadMail, SLOT(setEnabled(bool)));
978 // System tray modes
979 mSystemTrayGroup = new KButtonGroup(this);
980 mSystemTrayGroup->setTitle(i18n("System Tray Mode"));
981 QVBoxLayout *gvlay = new QVBoxLayout(mSystemTrayGroup);
982 //TODO PORT QT5 gvlay->setSpacing( QDialog::spacingHint() );
984 connect(mSystemTrayGroup, SIGNAL(clicked(int)),
985 this, SLOT(slotEmitChanged()));
986 connect(mSystemTrayCheck, SIGNAL(toggled(bool)),
987 mSystemTrayGroup, SLOT(setEnabled(bool)));
989 gvlay->addWidget(new QRadioButton(i18n("Always show KMail in system tray"), mSystemTrayGroup));
990 gvlay->addWidget(new QRadioButton(i18n("Only show KMail in system tray if there are unread messages"), mSystemTrayGroup));
992 vlay->addWidget(mSystemTrayGroup);
993 vlay->addStretch(10); // spacer
996 void AppearancePage::SystemTrayTab::doLoadFromGlobalSettings()
998 loadWidget(mSystemTrayCheck, GlobalSettings::self()->systemTrayEnabledItem());
999 loadWidget(mSystemTrayShowUnreadMail, GlobalSettings::self()->systemTrayShowUnreadItem());
1000 mSystemTrayGroup->setSelected(GlobalSettings::self()->systemTrayPolicy());
1001 mSystemTrayGroup->setEnabled(mSystemTrayCheck->isChecked());
1004 void AppearancePage::SystemTrayTab::save()
1006 saveCheckBox(mSystemTrayCheck, GlobalSettings::self()->systemTrayEnabledItem());
1007 GlobalSettings::self()->setSystemTrayPolicy(mSystemTrayGroup->selected());
1008 saveCheckBox(mSystemTrayShowUnreadMail, GlobalSettings::self()->systemTrayShowUnreadItem());
1009 GlobalSettings::self()->save();
1012 QString AppearancePage::MessageTagTab::helpAnchor() const
1014 return QString::fromLatin1("configure-appearance-messagetag");
1017 TagListWidgetItem::TagListWidgetItem(QListWidget *parent)
1018 : QListWidgetItem(parent), mTag(0)
1022 TagListWidgetItem::TagListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent)
1023 : QListWidgetItem(icon, text, parent), mTag(0)
1027 TagListWidgetItem::~TagListWidgetItem()
1031 void TagListWidgetItem::setKMailTag(const MailCommon::Tag::Ptr &tag)
1033 mTag = tag;
1036 MailCommon::Tag::Ptr TagListWidgetItem::kmailTag() const
1038 return mTag;
1041 AppearancePageMessageTagTab::AppearancePageMessageTagTab(QWidget *parent)
1042 : ConfigModuleTab(parent)
1044 mPreviousTag = -1;
1045 QHBoxLayout *maingrid = new QHBoxLayout(this);
1046 //TODO PORT QT5 maingrid->setMargin( QDialog::marginHint() );
1047 //TODO PORT QT5 maingrid->setSpacing( QDialog::spacingHint() );
1049 //Lefthand side Listbox and friends
1051 //Groupbox frame
1052 mTagsGroupBox = new QGroupBox(i18n("A&vailable Tags"), this);
1053 maingrid->addWidget(mTagsGroupBox);
1054 QVBoxLayout *tageditgrid = new QVBoxLayout(mTagsGroupBox);
1055 //TODO PORT QT5 tageditgrid->setMargin( QDialog::marginHint() );
1056 //TODO PORT QT5 tageditgrid->setSpacing( QDialog::spacingHint() );
1057 //TODO PORT QT5 tageditgrid->addSpacing( 2 * QDialog::spacingHint() );
1059 //Listbox, add, remove row
1060 QHBoxLayout *addremovegrid = new QHBoxLayout();
1061 tageditgrid->addLayout(addremovegrid);
1063 mTagAddLineEdit = new KLineEdit(mTagsGroupBox);
1064 mTagAddLineEdit->setTrapReturnKey(true);
1065 addremovegrid->addWidget(mTagAddLineEdit);
1067 mTagAddButton = new QPushButton(mTagsGroupBox);
1068 mTagAddButton->setToolTip(i18n("Add new tag"));
1069 mTagAddButton->setIcon(QIcon::fromTheme(QLatin1String("list-add")));
1070 addremovegrid->addWidget(mTagAddButton);
1072 mTagRemoveButton = new QPushButton(mTagsGroupBox);
1073 mTagRemoveButton->setToolTip(i18n("Remove selected tag"));
1074 mTagRemoveButton->setIcon(QIcon::fromTheme(QLatin1String("list-remove")));
1075 addremovegrid->addWidget(mTagRemoveButton);
1077 //Up and down buttons
1078 QHBoxLayout *updowngrid = new QHBoxLayout();
1079 tageditgrid->addLayout(updowngrid);
1081 mTagUpButton = new QPushButton(mTagsGroupBox);
1082 mTagUpButton->setToolTip(i18n("Increase tag priority"));
1083 mTagUpButton->setIcon(QIcon::fromTheme(QLatin1String("arrow-up")));
1084 mTagUpButton->setAutoRepeat(true);
1085 updowngrid->addWidget(mTagUpButton);
1087 mTagDownButton = new QPushButton(mTagsGroupBox);
1088 mTagDownButton->setToolTip(i18n("Decrease tag priority"));
1089 mTagDownButton->setIcon(QIcon::fromTheme(QLatin1String("arrow-down")));
1090 mTagDownButton->setAutoRepeat(true);
1091 updowngrid->addWidget(mTagDownButton);
1093 //Listbox for tag names
1094 QHBoxLayout *listboxgrid = new QHBoxLayout();
1095 tageditgrid->addLayout(listboxgrid);
1096 mTagListBox = new QListWidget(mTagsGroupBox);
1097 mTagListBox->setDragDropMode(QAbstractItemView::InternalMove);
1098 connect(mTagListBox->model(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(slotRowsMoved(QModelIndex,int,int,QModelIndex,int)));
1100 mTagListBox->setMinimumWidth(150);
1101 listboxgrid->addWidget(mTagListBox);
1103 //RHS for individual tag settings
1105 //Extra VBoxLayout for stretchers around settings
1106 QVBoxLayout *tagsettinggrid = new QVBoxLayout();
1107 maingrid->addLayout(tagsettinggrid);
1108 //tagsettinggrid->addStretch( 10 );
1110 //Groupbox frame
1111 mTagSettingGroupBox = new QGroupBox(i18n("Ta&g Settings"),
1112 this);
1113 tagsettinggrid->addWidget(mTagSettingGroupBox);
1114 QList<KActionCollection *> actionCollections;
1115 if (kmkernel->getKMMainWidget()) {
1116 actionCollections = kmkernel->getKMMainWidget()->actionCollections();
1119 QHBoxLayout *lay = new QHBoxLayout(mTagSettingGroupBox);
1120 mTagWidget = new MailCommon::TagWidget(actionCollections, this);
1121 lay->addWidget(mTagWidget);
1123 connect(mTagWidget, SIGNAL(changed()), this, SLOT(slotEmitChangeCheck()));
1125 //For enabling the add button in case box is non-empty
1126 connect(mTagAddLineEdit, SIGNAL(textChanged(QString)),
1127 this, SLOT(slotAddLineTextChanged(QString)));
1129 //For on-the-fly updating of tag name in editbox
1130 connect(mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
1131 this, SLOT(slotNameLineTextChanged(QString)));
1133 connect(mTagWidget, SIGNAL(iconNameChanged(QString)), SLOT(slotIconNameChanged(QString)));
1135 connect(mTagAddLineEdit, SIGNAL(returnPressed()),
1136 this, SLOT(slotAddNewTag()));
1138 connect(mTagAddButton, SIGNAL(clicked()),
1139 this, SLOT(slotAddNewTag()));
1141 connect(mTagRemoveButton, SIGNAL(clicked()),
1142 this, SLOT(slotRemoveTag()));
1144 connect(mTagUpButton, SIGNAL(clicked()),
1145 this, SLOT(slotMoveTagUp()));
1147 connect(mTagDownButton, SIGNAL(clicked()),
1148 this, SLOT(slotMoveTagDown()));
1150 connect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1151 this, SLOT(slotSelectionChanged()));
1152 //Adjust widths for columns
1153 maingrid->setStretchFactor(mTagsGroupBox, 1);
1154 maingrid->setStretchFactor(lay, 1);
1155 tagsettinggrid->addStretch(10);
1158 AppearancePageMessageTagTab::~AppearancePageMessageTagTab()
1162 void AppearancePage::MessageTagTab::slotEmitChangeCheck()
1164 slotEmitChanged();
1167 void AppearancePage::MessageTagTab::slotRowsMoved(const QModelIndex &,
1168 int sourcestart, int sourceEnd,
1169 const QModelIndex &, int destinationRow)
1171 Q_UNUSED(sourceEnd);
1172 Q_UNUSED(sourcestart);
1173 Q_UNUSED(destinationRow);
1174 updateButtons();
1175 slotEmitChangeCheck();
1178 void AppearancePage::MessageTagTab::updateButtons()
1180 const int currentIndex = mTagListBox->currentRow();
1182 const bool theFirst = (currentIndex == 0);
1183 const bool theLast = (currentIndex >= (int)mTagListBox->count() - 1);
1184 const bool aFilterIsSelected = (currentIndex >= 0);
1186 mTagUpButton->setEnabled(aFilterIsSelected && !theFirst);
1187 mTagDownButton->setEnabled(aFilterIsSelected && !theLast);
1190 void AppearancePage::MessageTagTab::slotMoveTagUp()
1192 const int tmp_index = mTagListBox->currentRow();
1193 if (tmp_index <= 0) {
1194 return;
1196 swapTagsInListBox(tmp_index, tmp_index - 1);
1197 updateButtons();
1200 void AppearancePage::MessageTagTab::slotMoveTagDown()
1202 const int tmp_index = mTagListBox->currentRow();
1203 if ((tmp_index < 0)
1204 || (tmp_index >= int(mTagListBox->count()) - 1)) {
1205 return;
1207 swapTagsInListBox(tmp_index, tmp_index + 1);
1208 updateButtons();
1211 void AppearancePage::MessageTagTab::swapTagsInListBox(const int first,
1212 const int second)
1214 disconnect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1215 this, SLOT(slotSelectionChanged()));
1216 QListWidgetItem *item = mTagListBox->takeItem(first);
1217 // now selected item is at idx(idx-1), so
1218 // insert the other item at idx, ie. above(below).
1219 mPreviousTag = second;
1220 mTagListBox->insertItem(second, item);
1221 mTagListBox->setCurrentRow(second);
1222 connect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1223 this, SLOT(slotSelectionChanged()));
1224 slotEmitChangeCheck();
1227 void AppearancePage::MessageTagTab::slotRecordTagSettings(int aIndex)
1229 if ((aIndex < 0) || (aIndex >= int(mTagListBox->count()))) {
1230 return;
1232 QListWidgetItem *item = mTagListBox->item(aIndex);
1233 TagListWidgetItem *tagItem = static_cast<TagListWidgetItem *>(item);
1235 MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag();
1237 tmp_desc->tagName = tagItem->text();
1238 mTagWidget->recordTagSettings(tmp_desc);
1241 void AppearancePage::MessageTagTab::slotUpdateTagSettingWidgets(int aIndex)
1243 //Check if selection is valid
1244 if ((aIndex < 0) || (mTagListBox->currentRow() < 0)) {
1245 mTagRemoveButton->setEnabled(false);
1246 mTagUpButton->setEnabled(false);
1247 mTagDownButton->setEnabled(false);
1249 mTagWidget->setEnabled(false);
1250 return;
1252 mTagWidget->setEnabled(true);
1254 mTagRemoveButton->setEnabled(true);
1255 mTagUpButton->setEnabled((0 != aIndex));
1256 mTagDownButton->setEnabled(((int(mTagListBox->count()) - 1) != aIndex));
1257 QListWidgetItem *item = mTagListBox->currentItem();
1258 TagListWidgetItem *tagItem = static_cast<TagListWidgetItem *>(item);
1259 MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag();
1261 disconnect(mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
1262 this, SLOT(slotNameLineTextChanged(QString)));
1264 mTagWidget->tagNameLineEdit()->setEnabled(!tmp_desc->isImmutable);
1265 mTagWidget->tagNameLineEdit()->setText(tmp_desc->tagName);
1266 connect(mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
1267 this, SLOT(slotNameLineTextChanged(QString)));
1269 mTagWidget->setTagTextColor(tmp_desc->textColor);
1271 mTagWidget->setTagBackgroundColor(tmp_desc->backgroundColor);
1273 mTagWidget->setTagTextFont(tmp_desc->textFont);
1275 mTagWidget->iconButton()->setEnabled(!tmp_desc->isImmutable);
1276 mTagWidget->iconButton()->setIcon(tmp_desc->iconName);
1278 mTagWidget->keySequenceWidget()->setEnabled(true);
1279 mTagWidget->keySequenceWidget()->setKeySequence(tmp_desc->shortcut,
1280 KKeySequenceWidget::NoValidate);
1282 mTagWidget->inToolBarCheck()->setEnabled(true);
1283 mTagWidget->inToolBarCheck()->setChecked(tmp_desc->inToolbar);
1286 void AppearancePage::MessageTagTab::slotSelectionChanged()
1288 mEmitChanges = false;
1289 slotRecordTagSettings(mPreviousTag);
1290 slotUpdateTagSettingWidgets(mTagListBox->currentRow());
1291 mPreviousTag = mTagListBox->currentRow();
1292 mEmitChanges = true;
1295 void AppearancePage::MessageTagTab::slotRemoveTag()
1297 const int tmp_index = mTagListBox->currentRow();
1298 if (tmp_index >= 0) {
1299 if (KMessageBox::Yes == KMessageBox::questionYesNo(this, i18n("Do you want to remove tag \'%1\'?", mTagListBox->item(mTagListBox->currentRow())->text()))) {
1300 QListWidgetItem *item = mTagListBox->takeItem(mTagListBox->currentRow());
1301 TagListWidgetItem *tagItem = static_cast<TagListWidgetItem *>(item);
1302 MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag();
1303 if (tmp_desc->tag().isValid()) {
1304 new Akonadi::TagDeleteJob(tmp_desc->tag());
1305 } else {
1306 qWarning() << "Can't remove tag with invalid akonadi tag";
1308 mPreviousTag = -1;
1310 //Before deleting the current item, make sure the selectionChanged signal
1311 //is disconnected, so that the widgets will not get updated while the
1312 //deletion takes place.
1313 disconnect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1314 this, SLOT(slotSelectionChanged()));
1316 delete item;
1317 connect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1318 this, SLOT(slotSelectionChanged()));
1320 slotSelectionChanged();
1321 slotEmitChangeCheck();
1326 void AppearancePage::MessageTagTab::slotDeleteTagJob(KJob *job)
1328 if (job->error()) {
1329 qWarning() << "Failed to delete tag " << job->errorString();
1333 void AppearancePage::MessageTagTab::slotNameLineTextChanged(const QString
1334 &aText)
1336 //If deleted all, leave the first character for the sake of not having an
1337 //empty tag name
1338 if (aText.isEmpty() && !mTagListBox->currentItem()) {
1339 return;
1342 const int count = mTagListBox->count();
1343 for (int i = 0; i < count; ++i) {
1344 if (mTagListBox->item(i)->text() == aText) {
1345 KMessageBox::error(this, i18n("We cannot create tag. A tag with same name already exists."));
1346 disconnect(mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
1347 this, SLOT(slotNameLineTextChanged(QString)));
1348 mTagWidget->tagNameLineEdit()->setText(mTagListBox->currentItem()->text());
1349 connect(mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
1350 this, SLOT(slotNameLineTextChanged(QString)));
1351 return;
1355 //Disconnect so the tag information is not saved and reloaded with every
1356 //letter
1357 disconnect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1358 this, SLOT(slotSelectionChanged()));
1360 mTagListBox->currentItem()->setText(aText);
1361 connect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1362 this, SLOT(slotSelectionChanged()));
1365 void AppearancePage::MessageTagTab::slotIconNameChanged(const QString &iconName)
1367 mTagListBox->currentItem()->setIcon(QIcon::fromTheme(iconName));
1370 void AppearancePage::MessageTagTab::slotAddLineTextChanged(const QString &aText)
1372 mTagAddButton->setEnabled(!aText.trimmed().isEmpty());
1375 void AppearancePage::MessageTagTab::slotAddNewTag()
1377 const QString newTagName = mTagAddLineEdit->text();
1378 const int count = mTagListBox->count();
1379 for (int i = 0; i < count; ++i) {
1380 if (mTagListBox->item(i)->text() == newTagName) {
1381 KMessageBox::error(this, i18n("We cannot create tag. A tag with same name already exists."));
1382 return;
1386 const int tmp_priority = mTagListBox->count();
1388 MailCommon::Tag::Ptr tag(Tag::createDefaultTag(newTagName));
1389 tag->priority = tmp_priority;
1391 slotEmitChangeCheck();
1392 TagListWidgetItem *newItem = new TagListWidgetItem(QIcon::fromTheme(tag->iconName), newTagName, mTagListBox);
1393 newItem->setKMailTag(tag);
1394 mTagListBox->addItem(newItem);
1395 mTagListBox->setCurrentItem(newItem);
1396 mTagAddLineEdit->setText(QString());
1399 void AppearancePage::MessageTagTab::doLoadFromGlobalSettings()
1401 mTagListBox->clear();
1403 Akonadi::TagFetchJob *fetchJob = new Akonadi::TagFetchJob(this);
1404 fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>();
1405 connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(slotTagsFetched(KJob*)));
1408 void AppearancePage::MessageTagTab::slotTagsFetched(KJob *job)
1410 if (job->error()) {
1411 qWarning() << "Failed to load tags " << job->errorString();
1412 return;
1414 Akonadi::TagFetchJob *fetchJob = static_cast<Akonadi::TagFetchJob *>(job);
1416 QList<MailCommon::TagPtr> msgTagList;
1417 foreach (const Akonadi::Tag &akonadiTag, fetchJob->tags()) {
1418 MailCommon::Tag::Ptr tag = MailCommon::Tag::fromAkonadi(akonadiTag);
1419 msgTagList.append(tag);
1422 qSort(msgTagList.begin(), msgTagList.end(), MailCommon::Tag::compare);
1424 foreach (const MailCommon::Tag::Ptr &tag, msgTagList) {
1425 TagListWidgetItem *newItem = new TagListWidgetItem(QIcon::fromTheme(tag->iconName), tag->tagName, mTagListBox);
1426 newItem->setKMailTag(tag);
1427 if (tag->priority == -1) {
1428 tag->priority = mTagListBox->count() - 1;
1432 //Disconnect so that insertItem's do not trigger an update procedure
1433 disconnect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1434 this, SLOT(slotSelectionChanged()));
1436 connect(mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1437 this, SLOT(slotSelectionChanged()));
1439 slotUpdateTagSettingWidgets(-1);
1440 //Needed since the previous function doesn't affect add button
1441 mTagAddButton->setEnabled(false);
1443 // Save the original list
1444 mOriginalMsgTagList.clear();
1445 foreach (const MailCommon::TagPtr &tag, msgTagList) {
1446 mOriginalMsgTagList.append(MailCommon::TagPtr(new MailCommon::Tag(*tag)));
1451 void AppearancePage::MessageTagTab::save()
1453 const int currentRow = mTagListBox->currentRow();
1454 if (currentRow < 0) {
1455 return;
1458 const int count = mTagListBox->count();
1459 if (!count) {
1460 return;
1463 QListWidgetItem *item = mTagListBox->currentItem();
1464 if (!item) {
1465 return;
1467 slotRecordTagSettings(currentRow);
1468 const int numberOfMsgTagList = count;
1469 for (int i = 0; i < numberOfMsgTagList; ++i) {
1470 TagListWidgetItem *tagItem = static_cast<TagListWidgetItem *>(mTagListBox->item(i));
1471 if ((i >= mOriginalMsgTagList.count()) || *(tagItem->kmailTag()) != *(mOriginalMsgTagList[i])) {
1472 MailCommon::Tag::Ptr tag = tagItem->kmailTag();
1473 tag->priority = i;
1475 MailCommon::Tag::SaveFlags saveFlags = mTagWidget->saveFlags();
1476 Akonadi::Tag akonadiTag = tag->saveToAkonadi(saveFlags);
1477 if ((*tag).id() > 0) {
1478 akonadiTag.setId((*tag).id());
1480 if (akonadiTag.isValid()) {
1481 new Akonadi::TagModifyJob(akonadiTag);
1482 } else {
1483 new Akonadi::TagCreateJob(akonadiTag);