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"
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>
59 #include <KFontChooser>
60 #include <QHBoxLayout>
61 #include <KMessageBox>
62 #include <KKeySequenceWidget>
68 #include <kmime/kmime_dateformatter.h>
69 using KMime::DateFormatter
;
72 #include <QButtonGroup>
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
)
89 mFontsTab
= new FontsTab();
90 addTab(mFontsTab
, i18n("Fonts"));
95 mColorsTab
= new ColorsTab();
96 addTab(mColorsTab
, i18n("Colors"));
101 mLayoutTab
= new LayoutTab();
102 addTab(mLayoutTab
, i18n("Layout"));
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
;
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
,
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]);
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);
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
]);
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()));
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:
378 new QCheckBox(i18n("Recycle colors on deep "ing"), 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);
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());
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
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
]));
464 mColorList
->setColorSilently(i
, reader
.readEntry(configName
, defaultColor
[i
]));
467 mColorList
->setColorSilently(i
, defaultColor
[i
]);
475 void AppearancePage::ColorsTab::doResetToDefaultsOther()
477 mCustomColorCheck
->setChecked(false);
478 mRecycleColorCheck
->setChecked(false);
479 mCloseToQuotaThreshold
->setValue(80);
483 void AppearancePage::ColorsTab::save()
485 if (!KMKernel::self()) {
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
));
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()));
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()));
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
;
734 if (QString::fromLatin1(label
).contains(QLatin1String("%1"))) {
735 buttonLabel
= i18n(label
, DateFormatter::formatCurrentDate(dateDisplayConfig
[i
].dateDisplay
));
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:"
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>"
780 "<p><strong>These expressions may be used for the time:"
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>"
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());
837 slotSelectDefaultAggregation();
840 slotSelectDefaultTheme();
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());
853 slotSelectDefaultAggregation();
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
);
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();
889 mAggregationComboBox
->writeDefaultConfig();
892 mThemeComboBox
->writeDefaultConfig();
894 const int dateDisplayID
= mDateDisplay
->selected();
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());
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)));
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
)
1036 MailCommon::Tag::Ptr
TagListWidgetItem::kmailTag() const
1041 AppearancePageMessageTagTab::AppearancePageMessageTagTab(QWidget
*parent
)
1042 : ConfigModuleTab(parent
)
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
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 );
1111 mTagSettingGroupBox
= new QGroupBox(i18n("Ta&g Settings"),
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()
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
);
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) {
1196 swapTagsInListBox(tmp_index
, tmp_index
- 1);
1200 void AppearancePage::MessageTagTab::slotMoveTagDown()
1202 const int tmp_index
= mTagListBox
->currentRow();
1204 || (tmp_index
>= int(mTagListBox
->count()) - 1)) {
1207 swapTagsInListBox(tmp_index
, tmp_index
+ 1);
1211 void AppearancePage::MessageTagTab::swapTagsInListBox(const int first
,
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()))) {
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);
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());
1306 qWarning() << "Can't remove tag with invalid akonadi tag";
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()));
1317 connect(mTagListBox
, SIGNAL(currentItemChanged(QListWidgetItem
*,QListWidgetItem
*)),
1318 this, SLOT(slotSelectionChanged()));
1320 slotSelectionChanged();
1321 slotEmitChangeCheck();
1326 void AppearancePage::MessageTagTab::slotDeleteTagJob(KJob
*job
)
1329 qWarning() << "Failed to delete tag " << job
->errorString();
1333 void AppearancePage::MessageTagTab::slotNameLineTextChanged(const QString
1336 //If deleted all, leave the first character for the sake of not having an
1338 if (aText
.isEmpty() && !mTagListBox
->currentItem()) {
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
)));
1355 //Disconnect so the tag information is not saved and reloaded with every
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."));
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
)
1411 qWarning() << "Failed to load tags " << job
->errorString();
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) {
1458 const int count
= mTagListBox
->count();
1463 QListWidgetItem
*item
= mTagListBox
->currentItem();
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();
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
);
1483 new Akonadi::TagCreateJob(akonadiTag
);