kde-playground/kdepim/kmail/configuredialog/configureappearancepage.cpp
2015-04-14 21:49:29 +00:00

1479 lines
60 KiB
C++

/*
Copyright (c) 2013, 2014 Montel Laurent <montel@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "configureappearancepage.h"
#include "pimcommon/widgets/configureimmutablewidgetutils.h"
using namespace PimCommon::ConfigureImmutableWidgetUtils;
#include "configuredialog/colorlistbox.h"
#include "messagelist/utils/aggregationcombobox.h"
#include "messagelist/utils/aggregationconfigbutton.h"
#include "messagelist/utils/themecombobox.h"
#include "messagelist/utils/themeconfigbutton.h"
#include "mailcommon/tag/tagwidget.h"
#include "mailcommon/tag/tag.h"
#include "kmkernel.h"
#include "util.h"
#include "foldertreewidget.h"
#include "kmmainwidget.h"
#include "foldertreewidget.h"
#include "mailcommon/mailcommonsettings_base.h"
#include "messageviewer/widgets/configurewidget.h"
#include "messageviewer/settings/globalsettings.h"
#include "messagelist/core/settings.h"
#include "messagelist/messagelistutil.h"
#include "messagecore/settings/globalsettings.h"
#include "settings/globalsettings.h"
#include "mailcommon/util/mailutil.h"
#include <Akonadi/Tag>
#include <Akonadi/TagFetchJob>
#include <Akonadi/TagFetchScope>
#include <Akonadi/TagDeleteJob>
#include <Akonadi/TagCreateJob>
#include <Akonadi/TagAttribute>
#include <Akonadi/TagModifyJob>
#include <KIconButton>
#include <KButtonGroup>
#include <KLocalizedString>
#include <KColorScheme>
#include <KSeparator>
#include <KFontChooser>
#include <KHBox>
#include <KMessageBox>
#include <KKeySequenceWidget>
#include <KLineEdit>
#include <KDialog>
#include <kmime/kmime_dateformatter.h>
using KMime::DateFormatter;
#include <QWhatsThis>
#include <QButtonGroup>
#include <QSpinBox>
#include <QLabel>
using namespace MailCommon;
QString AppearancePage::helpAnchor() const
{
return QString::fromLatin1("configure-appearance");
}
AppearancePage::AppearancePage( const KComponentData &instance, QWidget *parent )
: ConfigModuleWithTabs( instance, parent )
{
//
// "Fonts" tab:
//
mFontsTab = new FontsTab();
addTab( mFontsTab, i18n("Fonts") );
//
// "Colors" tab:
//
mColorsTab = new ColorsTab();
addTab( mColorsTab, i18n("Colors") );
//
// "Layout" tab:
//
mLayoutTab = new LayoutTab();
addTab( mLayoutTab, i18n("Layout") );
//
// "Headers" tab:
//
mHeadersTab = new HeadersTab();
addTab( mHeadersTab, i18n("Message List") );
//
// "Reader window" tab:
//
mReaderTab = new ReaderTab();
addTab( mReaderTab, i18n("Message Window") );
addConfig( MessageViewer::GlobalSettings::self(), mReaderTab );
//
// "System Tray" tab:
//
mSystemTrayTab = new SystemTrayTab();
addTab( mSystemTrayTab, i18n("System Tray") );
//
// "Message Tag" tab:
//
mMessageTagTab = new MessageTagTab();
addTab( mMessageTagTab, i18n("Message Tags") );
}
QString AppearancePage::FontsTab::helpAnchor() const
{
return QString::fromLatin1("configure-appearance-fonts");
}
static const struct {
const char * configName;
const char * displayName;
bool enableFamilyAndSize;
bool onlyFixed;
} fontNames[] = {
{ "body-font", I18N_NOOP("Message Body"), true, false },
{ "MessageListFont", I18N_NOOP("Message List"), true, false },
{ "UnreadMessageFont", I18N_NOOP("Message List - Unread Messages"), true, false },
{ "ImportantMessageFont", I18N_NOOP("Message List - Important Messages"), true, false },
{ "TodoMessageFont", I18N_NOOP("Message List - Action Item Messages"), true, false },
{ "folder-font", I18N_NOOP("Folder List"), true, false },
{ "quote1-font", I18N_NOOP("Quoted Text - First Level"), false, false },
{ "quote2-font", I18N_NOOP("Quoted Text - Second Level"), false, false },
{ "quote3-font", I18N_NOOP("Quoted Text - Third Level"), false, false },
{ "fixed-font", I18N_NOOP("Fixed Width Font"), true, true },
{ "composer-font", I18N_NOOP("Composer"), true, false },
{ "print-font", I18N_NOOP("Printing Output"), true, false },
};
static const int numFontNames = sizeof fontNames / sizeof *fontNames;
AppearancePageFontsTab::AppearancePageFontsTab( QWidget * parent )
: ConfigModuleTab( parent ), mActiveFontIndex( -1 )
{
assert( numFontNames == sizeof mFont / sizeof *mFont );
// "Use custom fonts" checkbox, followed by <hr>
QVBoxLayout *vlay = new QVBoxLayout( this );
vlay->setSpacing( KDialog::spacingHint() );
vlay->setMargin( KDialog::marginHint() );
mCustomFontCheck = new QCheckBox( i18n("&Use custom fonts"), this );
vlay->addWidget( mCustomFontCheck );
vlay->addWidget( new KSeparator( Qt::Horizontal, this ) );
connect ( mCustomFontCheck, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
// "font location" combo box and label:
QHBoxLayout *hlay = new QHBoxLayout(); // inherites spacing
vlay->addLayout( hlay );
mFontLocationCombo = new KComboBox( this );
mFontLocationCombo->setEditable( false );
mFontLocationCombo->setEnabled( false ); // !mCustomFontCheck->isChecked()
QStringList fontDescriptions;
for ( int i = 0 ; i < numFontNames ; ++i )
fontDescriptions << i18n( fontNames[i].displayName );
mFontLocationCombo->addItems( fontDescriptions );
QLabel *label = new QLabel( i18n("Apply &to:"), this );
label->setBuddy( mFontLocationCombo );
label->setEnabled( false ); // since !mCustomFontCheck->isChecked()
hlay->addWidget( label );
hlay->addWidget( mFontLocationCombo );
hlay->addStretch( 10 );
vlay->addSpacing( KDialog::spacingHint() );
mFontChooser = new KFontChooser( this, KFontChooser::DisplayFrame,
QStringList(), 4 );
mFontChooser->setEnabled( false ); // since !mCustomFontCheck->isChecked()
vlay->addWidget( mFontChooser );
connect ( mFontChooser, SIGNAL(fontSelected(QFont)),
this, SLOT(slotEmitChanged()) );
// {en,dis}able widgets depending on the state of mCustomFontCheck:
connect( mCustomFontCheck, SIGNAL(toggled(bool)),
label, SLOT(setEnabled(bool)) );
connect( mCustomFontCheck, SIGNAL(toggled(bool)),
mFontLocationCombo, SLOT(setEnabled(bool)) );
connect( mCustomFontCheck, SIGNAL(toggled(bool)),
mFontChooser, SLOT(setEnabled(bool)) );
// load the right font settings into mFontChooser:
connect( mFontLocationCombo, SIGNAL(activated(int)),
this, SLOT(slotFontSelectorChanged(int)) );
}
void AppearancePage::FontsTab::slotFontSelectorChanged( int index )
{
kDebug() << "slotFontSelectorChanged() called";
if( index < 0 || index >= mFontLocationCombo->count() )
return; // Should never happen, but it is better to check.
// Save current fontselector setting before we install the new:
if( mActiveFontIndex == 0 ) {
mFont[0] = mFontChooser->font();
// hardcode the family and size of "message body" dependant fonts:
for ( int i = 0 ; i < numFontNames ; ++i )
if ( !fontNames[i].enableFamilyAndSize ) {
// ### shall we copy the font and set the save and re-set
// {regular,italic,bold,bold italic} property or should we
// copy only family and pointSize?
mFont[i].setFamily( mFont[0].family() );
mFont[i].setPointSize/*Float?*/( mFont[0].pointSize/*Float?*/() );
}
} else if ( mActiveFontIndex > 0 )
mFont[ mActiveFontIndex ] = mFontChooser->font();
mActiveFontIndex = index;
// Disonnect so the "Apply" button is not activated by the change
disconnect ( mFontChooser, SIGNAL(fontSelected(QFont)),
this, SLOT(slotEmitChanged()) );
// Display the new setting:
mFontChooser->setFont( mFont[index], fontNames[index].onlyFixed );
connect ( mFontChooser, SIGNAL(fontSelected(QFont)),
this, SLOT(slotEmitChanged()) );
// Disable Family and Size list if we have selected a quote font:
mFontChooser->enableColumn( KFontChooser::FamilyList|KFontChooser::SizeList,
fontNames[ index ].enableFamilyAndSize );
}
void AppearancePage::FontsTab::doLoadOther()
{
if (KMKernel::self()) {
KConfigGroup fonts( KMKernel::self()->config(), "Fonts" );
KConfigGroup messagelistFont( KMKernel::self()->config(), "MessageListView::Fonts" );
mFont[0] = KGlobalSettings::generalFont();
QFont fixedFont = KGlobalSettings::fixedFont();
for ( int i = 0 ; i < numFontNames ; ++i ) {
const QString configName = QLatin1String(fontNames[i].configName);
if ( configName == QLatin1String( "MessageListFont" ) ||
configName == QLatin1String( "UnreadMessageFont" ) ||
configName == QLatin1String( "ImportantMessageFont" ) ||
configName == QLatin1String( "TodoMessageFont" ) ) {
mFont[i] = messagelistFont.readEntry( configName,
(fontNames[i].onlyFixed) ? fixedFont : mFont[0] );
} else {
mFont[i] = fonts.readEntry( configName,
(fontNames[i].onlyFixed) ? fixedFont : mFont[0] );
}
}
mCustomFontCheck->setChecked( !MessageCore::GlobalSettings::self()->useDefaultFonts() );
mFontLocationCombo->setCurrentIndex( 0 );
slotFontSelectorChanged( 0 );
} else {
setEnabled(false);
}
}
void AppearancePage::FontsTab::save()
{
if (KMKernel::self()) {
KConfigGroup fonts( KMKernel::self()->config(), "Fonts" );
KConfigGroup messagelistFont( KMKernel::self()->config(), "MessageListView::Fonts" );
// read the current font (might have been modified)
if ( mActiveFontIndex >= 0 )
mFont[ mActiveFontIndex ] = mFontChooser->font();
const bool customFonts = mCustomFontCheck->isChecked();
MessageCore::GlobalSettings::self()->setUseDefaultFonts( !customFonts );
for ( int i = 0 ; i < numFontNames ; ++i ) {
const QString configName = QLatin1String(fontNames[i].configName);
if ( configName == QLatin1String( "MessageListFont" ) ||
configName == QLatin1String( "UnreadMessageFont" ) ||
configName == QLatin1String( "ImportantMessageFont" ) ||
configName == QLatin1String( "TodoMessageFont" ) ) {
if ( customFonts || messagelistFont.hasKey( configName ) ) {
// Don't write font info when we use default fonts, but write
// if it's already there:
messagelistFont.writeEntry( configName, mFont[i] );
}
} else {
if ( customFonts || fonts.hasKey( configName ) )
// Don't write font info when we use default fonts, but write
// if it's already there:
fonts.writeEntry( configName, mFont[i] );
}
}
}
}
void AppearancePage::FontsTab::doResetToDefaultsOther()
{
mCustomFontCheck->setChecked( false );
}
QString AppearancePage::ColorsTab::helpAnchor() const
{
return QString::fromLatin1("configure-appearance-colors");
}
static const struct {
const char * configName;
const char * displayName;
} colorNames[] = { // adjust doLoadOther if you change this:
{ "QuotedText1", I18N_NOOP("Quoted Text - First Level") },
{ "QuotedText2", I18N_NOOP("Quoted Text - Second Level") },
{ "QuotedText3", I18N_NOOP("Quoted Text - Third Level") },
{ "LinkColor", I18N_NOOP("Link") },
{ "FollowedColor", I18N_NOOP("Followed Link") },
{ "MisspelledColor", I18N_NOOP("Misspelled Words") },
{ "UnreadMessageColor", I18N_NOOP("Unread Message") },
{ "ImportantMessageColor", I18N_NOOP("Important Message") },
{ "TodoMessageColor", I18N_NOOP("Action Item Message") },
{ "PGPMessageEncr", I18N_NOOP("OpenPGP Message - Encrypted") },
{ "PGPMessageOkKeyOk", I18N_NOOP("OpenPGP Message - Valid Signature with Trusted Key") },
{ "PGPMessageOkKeyBad", I18N_NOOP("OpenPGP Message - Valid Signature with Untrusted Key") },
{ "PGPMessageWarn", I18N_NOOP("OpenPGP Message - Unchecked Signature") },
{ "PGPMessageErr", I18N_NOOP("OpenPGP Message - Bad Signature") },
{ "HTMLWarningColor", I18N_NOOP("Border Around Warning Prepending HTML Messages") },
{ "CloseToQuotaColor", I18N_NOOP("Folder Name and Size When Close to Quota") },
{ "ColorbarBackgroundPlain", I18N_NOOP("HTML Status Bar Background - No HTML Message") },
{ "ColorbarForegroundPlain", I18N_NOOP("HTML Status Bar Foreground - No HTML Message") },
{ "ColorbarBackgroundHTML", I18N_NOOP("HTML Status Bar Background - HTML Message") },
{ "ColorbarForegroundHTML", I18N_NOOP("HTML Status Bar Foreground - HTML Message") },
{ "BrokenAccountColor", I18N_NOOP("Broken Account - Folder Text Color") },
{ "BackgroundColor", I18N_NOOP("Background Color") },
};
static const int numColorNames = sizeof colorNames / sizeof *colorNames;
AppearancePageColorsTab::AppearancePageColorsTab( QWidget * parent )
: ConfigModuleTab( parent )
{
// "use custom colors" check box
QVBoxLayout *vlay = new QVBoxLayout( this );
vlay->setSpacing( KDialog::spacingHint() );
vlay->setMargin( KDialog::marginHint() );
mCustomColorCheck = new QCheckBox( i18n("&Use custom colors"), this );
vlay->addWidget( mCustomColorCheck );
connect( mCustomColorCheck, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
// color list box:
mColorList = new ColorListBox( this );
mColorList->setEnabled( false ); // since !mCustomColorCheck->isChecked()
for ( int i = 0 ; i < numColorNames ; ++i )
mColorList->addColor( i18n(colorNames[i].displayName) );
vlay->addWidget( mColorList, 1 );
// "recycle colors" check box:
mRecycleColorCheck =
new QCheckBox( i18n("Recycle colors on deep &quoting"), this );
mRecycleColorCheck->setEnabled( false );
vlay->addWidget( mRecycleColorCheck );
connect( mRecycleColorCheck, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
// close to quota threshold
QHBoxLayout *hbox = new QHBoxLayout();
vlay->addLayout( hbox );
QLabel *l = new QLabel( i18n("Close to quota threshold:"), this );
hbox->addWidget( l );
mCloseToQuotaThreshold = new QSpinBox( this );
mCloseToQuotaThreshold->setRange( 0, 100 );
mCloseToQuotaThreshold->setSingleStep( 1 );
connect( mCloseToQuotaThreshold, SIGNAL(valueChanged(int)),
this, SLOT(slotEmitChanged()) );
mCloseToQuotaThreshold->setSuffix( i18n("%"));
hbox->addWidget( mCloseToQuotaThreshold );
hbox->addWidget( new QWidget(this), 2 );
// {en,dir}able widgets depending on the state of mCustomColorCheck:
connect( mCustomColorCheck, SIGNAL(toggled(bool)),
mColorList, SLOT(setEnabled(bool)) );
connect( mCustomColorCheck, SIGNAL(toggled(bool)),
mRecycleColorCheck, SLOT(setEnabled(bool)) );
connect( mCustomColorCheck, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
connect( mColorList, SIGNAL(changed()),
this, SLOT(slotEmitChanged()) );
}
void AppearancePage::ColorsTab::doLoadOther()
{
mCustomColorCheck->setChecked( !MessageCore::GlobalSettings::self()->useDefaultColors() );
mRecycleColorCheck->setChecked( MessageViewer::GlobalSettings::self()->recycleQuoteColors() );
mCloseToQuotaThreshold->setValue( GlobalSettings::self()->closeToQuotaThreshold() );
loadColor( true );
}
void AppearancePage::ColorsTab::loadColor( bool loadFromConfig )
{
if (KMKernel::self()) {
KColorScheme scheme( QPalette::Active, KColorScheme::View );
KConfigGroup reader( KMKernel::self()->config(), "Reader" );
KConfigGroup messageListView( KMKernel::self()->config(), "MessageListView::Colors" );
KConfigGroup collectionFolderView( KMKernel::self()->config(), "CollectionFolderView" );
static const QColor defaultColor[ numColorNames ] = {
KMail::Util::quoteL1Color(),
KMail::Util::quoteL2Color(),
KMail::Util::quoteL3Color(),
scheme.foreground( KColorScheme::LinkText ).color(), // link
scheme.foreground( KColorScheme::VisitedText ).color(),// visited link
scheme.foreground( KColorScheme::NegativeText ).color(), // misspelled words
MessageList::Util::unreadDefaultMessageColor(), // unread mgs
MessageList::Util::importantDefaultMessageColor(), // important msg
MessageList::Util::todoDefaultMessageColor(), // action item mgs
QColor( 0x00, 0x80, 0xFF ), // pgp encrypted
scheme.background( KColorScheme::PositiveBackground ).color(), // pgp ok, trusted key
QColor( 0xFF, 0xFF, 0x40 ), // pgp ok, untrusted key
QColor( 0xFF, 0xFF, 0x40 ), // pgp unchk
Qt::red, // pgp bad
QColor( 0xFF, 0x40, 0x40 ), // warning text color
MailCommon::Util::defaultQuotaColor(), // close to quota
Qt::lightGray, // colorbar plain bg
Qt::black, // colorbar plain fg
Qt::black, // colorbar html bg
Qt::white, // colorbar html fg
scheme.foreground(KColorScheme::NegativeText).color(), //Broken Account Color
scheme.background().color() // reader background color
};
for ( int i = 0 ; i < numColorNames ; ++i ) {
if ( loadFromConfig ) {
const QString configName = QLatin1String(colorNames[i].configName);
if ( configName == QLatin1String( "UnreadMessageColor" ) ||
configName == QLatin1String( "ImportantMessageColor" ) ||
configName == QLatin1String( "TodoMessageColor" ) ) {
mColorList->setColorSilently( i, messageListView.readEntry( configName, defaultColor[i] ) );
} else if( configName == QLatin1String("BrokenAccountColor")) {
mColorList->setColorSilently( i, collectionFolderView.readEntry(configName,defaultColor[i]));
} else {
mColorList->setColorSilently( i, reader.readEntry( configName, defaultColor[i] ) );
}
} else {
mColorList->setColorSilently( i, defaultColor[i] );
}
}
} else {
setEnabled(false);
}
}
void AppearancePage::ColorsTab::doResetToDefaultsOther()
{
mCustomColorCheck->setChecked( false );
mRecycleColorCheck->setChecked( false );
mCloseToQuotaThreshold->setValue( 80 );
loadColor( false );
}
void AppearancePage::ColorsTab::save()
{
if (!KMKernel::self())
return;
KConfigGroup reader( KMKernel::self()->config(), "Reader" );
KConfigGroup messageListView( KMKernel::self()->config(), "MessageListView::Colors" );
KConfigGroup collectionFolderView( KMKernel::self()->config(), "CollectionFolderView" );
bool customColors = mCustomColorCheck->isChecked();
MessageCore::GlobalSettings::self()->setUseDefaultColors( !customColors );
KColorScheme scheme( QPalette::Active, KColorScheme::View );
for ( int i = 0 ; i < numColorNames ; ++i ) {
// Don't write color info when we use default colors, but write
// if it's already there:
const QString configName = QLatin1String(colorNames[i].configName);
if ( configName == QLatin1String( "UnreadMessageColor" ) ||
configName == QLatin1String( "ImportantMessageColor" ) ||
configName == QLatin1String( "TodoMessageColor" ) ) {
if ( customColors || messageListView.hasKey( configName ) )
messageListView.writeEntry( configName, mColorList->color(i) );
} else if( configName == QLatin1String("BrokenAccountColor")) {
if ( customColors || collectionFolderView.hasKey( configName ) )
collectionFolderView.writeEntry(configName,mColorList->color(i));
} else if (configName == QLatin1String("BackgroundColor")) {
if (customColors && (mColorList->color(i) != scheme.background().color() ))
reader.writeEntry(configName, mColorList->color(i));
} else {
if ( customColors || reader.hasKey( configName ) )
reader.writeEntry( configName, mColorList->color(i) );
}
}
MessageViewer::GlobalSettings::self()->setRecycleQuoteColors( mRecycleColorCheck->isChecked() );
GlobalSettings::self()->setCloseToQuotaThreshold( mCloseToQuotaThreshold->value() );
}
QString AppearancePage::LayoutTab::helpAnchor() const
{
return QString::fromLatin1("configure-appearance-layout");
}
AppearancePageLayoutTab::AppearancePageLayoutTab( QWidget * parent )
: ConfigModuleTab( parent )
{
QVBoxLayout *vlay = new QVBoxLayout( this );
vlay->setSpacing( KDialog::spacingHint() );
vlay->setMargin( KDialog::marginHint() );
// "folder list" radio buttons:
populateButtonGroup( mFolderListGroupBox = new QGroupBox( this ),
mFolderListGroup = new QButtonGroup( this ),
Qt::Vertical, GlobalSettings::self()->folderListItem() );
vlay->addWidget( mFolderListGroupBox );
connect( mFolderListGroup, SIGNAL (buttonClicked(int)),
this, SLOT(slotEmitChanged()) );
QHBoxLayout* folderCBHLayout = new QHBoxLayout();
mFolderQuickSearchCB = new QCheckBox( i18n("Show folder quick search field"), this );
connect( mFolderQuickSearchCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) );
folderCBHLayout->addWidget( mFolderQuickSearchCB );
vlay->addLayout( folderCBHLayout );
vlay->addSpacing( KDialog::spacingHint() ); // space before next box
// "favorite folders view mode" radio buttons:
mFavoriteFoldersViewGroupBox = new QGroupBox( this );
mFavoriteFoldersViewGroupBox->setTitle( i18n( "Show Favorite Folders View" ) );
mFavoriteFoldersViewGroupBox->setLayout( new QVBoxLayout() );
mFavoriteFoldersViewGroupBox->layout()->setSpacing( KDialog::spacingHint() );
mFavoriteFoldersViewGroup = new QButtonGroup( this );
connect( mFavoriteFoldersViewGroup, SIGNAL(buttonClicked(int)),
this, SLOT(slotEmitChanged()) );
QRadioButton* favoriteFoldersViewHiddenRadio = new QRadioButton( i18n( "Never" ), mFavoriteFoldersViewGroupBox );
mFavoriteFoldersViewGroup->addButton( favoriteFoldersViewHiddenRadio, static_cast<int>( MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode ) );
mFavoriteFoldersViewGroupBox->layout()->addWidget( favoriteFoldersViewHiddenRadio );
QRadioButton* favoriteFoldersViewIconsRadio = new QRadioButton( i18n( "As icons" ), mFavoriteFoldersViewGroupBox );
mFavoriteFoldersViewGroup->addButton( favoriteFoldersViewIconsRadio, static_cast<int>( MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode ) );
mFavoriteFoldersViewGroupBox->layout()->addWidget( favoriteFoldersViewIconsRadio );
QRadioButton* favoriteFoldersViewListRadio = new QRadioButton( i18n( "As list" ), mFavoriteFoldersViewGroupBox );
mFavoriteFoldersViewGroup->addButton( favoriteFoldersViewListRadio, static_cast<int>( MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode ) );
mFavoriteFoldersViewGroupBox->layout()->addWidget( favoriteFoldersViewListRadio );
vlay->addWidget( mFavoriteFoldersViewGroupBox );
// "folder tooltips" radio buttons:
mFolderToolTipsGroupBox = new QGroupBox( this );
mFolderToolTipsGroupBox->setTitle( i18n( "Folder Tooltips" ) );
mFolderToolTipsGroupBox->setLayout( new QVBoxLayout() );
mFolderToolTipsGroupBox->layout()->setSpacing( KDialog::spacingHint() );
mFolderToolTipsGroup = new QButtonGroup( this );
connect( mFolderToolTipsGroup, SIGNAL(buttonClicked(int)),
this, SLOT(slotEmitChanged()) );
QRadioButton* folderToolTipsAlwaysRadio = new QRadioButton( i18n( "Always" ), mFolderToolTipsGroupBox );
mFolderToolTipsGroup->addButton( folderToolTipsAlwaysRadio, static_cast< int >( FolderTreeWidget::DisplayAlways ) );
mFolderToolTipsGroupBox->layout()->addWidget( folderToolTipsAlwaysRadio );
QRadioButton* folderToolTipsNeverRadio = new QRadioButton( i18n( "Never" ), mFolderToolTipsGroupBox );
mFolderToolTipsGroup->addButton( folderToolTipsNeverRadio, static_cast< int >( FolderTreeWidget::DisplayNever ) );
mFolderToolTipsGroupBox->layout()->addWidget( folderToolTipsNeverRadio );
vlay->addWidget( mFolderToolTipsGroupBox );
// "show reader window" radio buttons:
populateButtonGroup( mReaderWindowModeGroupBox = new QGroupBox( this ),
mReaderWindowModeGroup = new QButtonGroup( this ),
Qt::Vertical, GlobalSettings::self()->readerWindowModeItem() );
vlay->addWidget( mReaderWindowModeGroupBox );
connect( mReaderWindowModeGroup, SIGNAL (buttonClicked(int)),
this, SLOT(slotEmitChanged()) );
vlay->addStretch( 10 ); // spacer
}
void AppearancePage::LayoutTab::doLoadOther()
{
loadWidget( mFolderListGroupBox, mFolderListGroup, GlobalSettings::self()->folderListItem() );
loadWidget( mReaderWindowModeGroupBox, mReaderWindowModeGroup, GlobalSettings::self()->readerWindowModeItem() );
loadWidget( mFavoriteFoldersViewGroupBox, mFavoriteFoldersViewGroup, MailCommon::MailCommonSettings::self()->favoriteCollectionViewModeItem() );
loadWidget( mFolderQuickSearchCB, GlobalSettings::self()->enableFolderQuickSearchItem() );
const int checkedFolderToolTipsPolicy = GlobalSettings::self()->toolTipDisplayPolicy();
if ( checkedFolderToolTipsPolicy >= 0 )
mFolderToolTipsGroup->button(checkedFolderToolTipsPolicy)->setChecked( true );
}
void AppearancePage::LayoutTab::save()
{
saveButtonGroup( mFolderListGroup, GlobalSettings::self()->folderListItem() );
saveButtonGroup( mReaderWindowModeGroup, GlobalSettings::self()->readerWindowModeItem() );
saveButtonGroup( mFavoriteFoldersViewGroup, MailCommon::MailCommonSettings::self()->favoriteCollectionViewModeItem() );
saveCheckBox( mFolderQuickSearchCB, GlobalSettings::self()->enableFolderQuickSearchItem() );
GlobalSettings::self()->setToolTipDisplayPolicy( mFolderToolTipsGroup->checkedId() );
}
//
// Appearance Message List
//
QString AppearancePage::HeadersTab::helpAnchor() const
{
return QString::fromLatin1("configure-appearance-headers");
}
static const struct {
const char * displayName;
DateFormatter::FormatType dateDisplay;
} dateDisplayConfig[] = {
{ I18N_NOOP("Sta&ndard format (%1)"), KMime::DateFormatter::CTime },
{ I18N_NOOP("Locali&zed format (%1)"), KMime::DateFormatter::Localized },
{ I18N_NOOP("Smart for&mat (%1)"), KMime::DateFormatter::Fancy },
{ I18N_NOOP("C&ustom format:"), KMime::DateFormatter::Custom }
};
static const int numDateDisplayConfig =
sizeof dateDisplayConfig / sizeof *dateDisplayConfig;
AppearancePageHeadersTab::AppearancePageHeadersTab( QWidget * parent )
: ConfigModuleTab( parent ),
mCustomDateFormatEdit( 0 )
{
QVBoxLayout *vlay = new QVBoxLayout( this );
vlay->setSpacing( KDialog::spacingHint() );
vlay->setMargin( KDialog::marginHint() );
// "General Options" group:
QGroupBox *group = new QGroupBox( i18nc( "General options for the message list.", "General" ), this );
// group->layout()->setSpacing( KDialog::spacingHint() );
QVBoxLayout *gvlay = new QVBoxLayout( group );
gvlay->setSpacing( KDialog::spacingHint() );
mDisplayMessageToolTips = new QCheckBox(
MessageList::Core::Settings::self()->messageToolTipEnabledItem()->label(), group );
gvlay->addWidget( mDisplayMessageToolTips );
connect( mDisplayMessageToolTips, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
mHideTabBarWithSingleTab = new QCheckBox(
MessageList::Core::Settings::self()->autoHideTabBarWithSingleTabItem()->label(), group );
gvlay->addWidget( mHideTabBarWithSingleTab );
connect( mHideTabBarWithSingleTab, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
mTabsHaveCloseButton = new QCheckBox(
MessageList::Core::Settings::self()->tabsHaveCloseButtonItem()->label(), group );
gvlay->addWidget( mTabsHaveCloseButton );
connect( mTabsHaveCloseButton, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
// "Aggregation"
using MessageList::Utils::AggregationComboBox;
mAggregationComboBox = new AggregationComboBox( group );
QLabel* aggregationLabel = new QLabel( i18n( "Default aggregation:" ), group );
aggregationLabel->setBuddy( mAggregationComboBox );
using MessageList::Utils::AggregationConfigButton;
AggregationConfigButton * aggregationConfigButton = new AggregationConfigButton( group, mAggregationComboBox );
QHBoxLayout * aggregationLayout = new QHBoxLayout();
aggregationLayout->addWidget( aggregationLabel, 1 );
aggregationLayout->addWidget( mAggregationComboBox, 1 );
aggregationLayout->addWidget( aggregationConfigButton, 0 );
gvlay->addLayout( aggregationLayout );
connect( aggregationConfigButton, SIGNAL(configureDialogCompleted()),
this, SLOT(slotSelectDefaultAggregation()) );
connect( mAggregationComboBox, SIGNAL(activated(int)),
this, SLOT(slotEmitChanged()) );
// "Theme"
using MessageList::Utils::ThemeComboBox;
mThemeComboBox = new ThemeComboBox( group );
QLabel *themeLabel = new QLabel( i18n( "Default theme:" ), group );
themeLabel->setBuddy( mThemeComboBox );
using MessageList::Utils::ThemeConfigButton;
ThemeConfigButton * themeConfigButton = new ThemeConfigButton( group, mThemeComboBox );
QHBoxLayout * themeLayout = new QHBoxLayout();
themeLayout->addWidget( themeLabel, 1 );
themeLayout->addWidget( mThemeComboBox, 1 );
themeLayout->addWidget( themeConfigButton, 0 );
gvlay->addLayout( themeLayout );
connect( themeConfigButton, SIGNAL(configureDialogCompleted()),
this, SLOT(slotSelectDefaultTheme()) );
connect( mThemeComboBox, SIGNAL(activated(int)),
this, SLOT(slotEmitChanged()) );
vlay->addWidget( group );
// "Date Display" group:
mDateDisplay = new KButtonGroup( this );
mDateDisplay->setTitle( i18n("Date Display") );
gvlay = new QVBoxLayout( mDateDisplay );
gvlay->setSpacing( KDialog::spacingHint() );
for ( int i = 0 ; i < numDateDisplayConfig ; ++i ) {
const char *label = dateDisplayConfig[i].displayName;
QString buttonLabel;
if ( QString::fromLatin1(label).contains(QLatin1String("%1")) )
buttonLabel = i18n( label, DateFormatter::formatCurrentDate( dateDisplayConfig[i].dateDisplay) );
else
buttonLabel = i18n( label );
QRadioButton *radio = new QRadioButton( buttonLabel, mDateDisplay );
gvlay->addWidget( radio );
if ( dateDisplayConfig[i].dateDisplay == DateFormatter::Custom ) {
KHBox *hbox = new KHBox( mDateDisplay );
hbox->setSpacing( KDialog::spacingHint() );
mCustomDateFormatEdit = new KLineEdit( hbox );
mCustomDateFormatEdit->setEnabled( false );
hbox->setStretchFactor( mCustomDateFormatEdit, 1 );
connect( radio, SIGNAL(toggled(bool)),
mCustomDateFormatEdit, SLOT(setEnabled(bool)) );
connect( mCustomDateFormatEdit, SIGNAL(textChanged(QString)),
this, SLOT(slotEmitChanged()) );
QLabel *formatHelp = new QLabel(
i18n( "<qt><a href=\"whatsthis1\">Custom format information...</a></qt>"), hbox );
formatHelp->setContextMenuPolicy(Qt::NoContextMenu);
connect( formatHelp, SIGNAL(linkActivated(QString)),
SLOT(slotLinkClicked(QString)) );
mCustomDateWhatsThis =
i18n("<qt><p><strong>These expressions may be used for the date:"
"</strong></p>"
"<ul>"
"<li>d - the day as a number without a leading zero (1-31)</li>"
"<li>dd - the day as a number with a leading zero (01-31)</li>"
"<li>ddd - the abbreviated day name (Mon - Sun)</li>"
"<li>dddd - the long day name (Monday - Sunday)</li>"
"<li>M - the month as a number without a leading zero (1-12)</li>"
"<li>MM - the month as a number with a leading zero (01-12)</li>"
"<li>MMM - the abbreviated month name (Jan - Dec)</li>"
"<li>MMMM - the long month name (January - December)</li>"
"<li>yy - the year as a two digit number (00-99)</li>"
"<li>yyyy - the year as a four digit number (0000-9999)</li>"
"</ul>"
"<p><strong>These expressions may be used for the time:"
"</strong></p> "
"<ul>"
"<li>h - the hour without a leading zero (0-23 or 1-12 if AM/PM display)</li>"
"<li>hh - the hour with a leading zero (00-23 or 01-12 if AM/PM display)</li>"
"<li>m - the minutes without a leading zero (0-59)</li>"
"<li>mm - the minutes with a leading zero (00-59)</li>"
"<li>s - the seconds without a leading zero (0-59)</li>"
"<li>ss - the seconds with a leading zero (00-59)</li>"
"<li>z - the milliseconds without leading zeroes (0-999)</li>"
"<li>zzz - the milliseconds with leading zeroes (000-999)</li>"
"<li>AP - switch to AM/PM display. AP will be replaced by either \"AM\" or \"PM\".</li>"
"<li>ap - switch to AM/PM display. ap will be replaced by either \"am\" or \"pm\".</li>"
"<li>Z - time zone in numeric form (-0500)</li>"
"</ul>"
"<p><strong>All other input characters will be ignored."
"</strong></p></qt>");
mCustomDateFormatEdit->setWhatsThis( mCustomDateWhatsThis );
radio->setWhatsThis( mCustomDateWhatsThis );
gvlay->addWidget( hbox );
} } // end for loop populating mDateDisplay
vlay->addWidget( mDateDisplay );
connect( mDateDisplay, SIGNAL(clicked(int)),
this, SLOT(slotEmitChanged()) );
vlay->addStretch( 10 ); // spacer
}
void AppearancePageHeadersTab::slotLinkClicked( const QString & link )
{
if ( link == QLatin1String( "whatsthis1" ) )
QWhatsThis::showText( QCursor::pos(), mCustomDateWhatsThis );
}
void AppearancePage::HeadersTab::slotSelectDefaultAggregation()
{
// Select current default aggregation.
mAggregationComboBox->selectDefault();
}
void AppearancePage::HeadersTab::slotSelectDefaultTheme()
{
// Select current default theme.
mThemeComboBox->selectDefault();
}
void AppearancePage::HeadersTab::doLoadOther()
{
// "General Options":
loadWidget(mDisplayMessageToolTips, MessageList::Core::Settings::self()->messageToolTipEnabledItem());
loadWidget(mHideTabBarWithSingleTab, MessageList::Core::Settings::self()->autoHideTabBarWithSingleTabItem() );
loadWidget(mTabsHaveCloseButton, MessageList::Core::Settings::self()->tabsHaveCloseButtonItem() );
// "Aggregation":
slotSelectDefaultAggregation();
// "Theme":
slotSelectDefaultTheme();
// "Date Display":
setDateDisplay( MessageCore::GlobalSettings::self()->dateFormat(),
MessageCore::GlobalSettings::self()->customDateFormat() );
}
void AppearancePage::HeadersTab::doLoadFromGlobalSettings()
{
loadWidget(mDisplayMessageToolTips, MessageList::Core::Settings::self()->messageToolTipEnabledItem());
loadWidget(mHideTabBarWithSingleTab, MessageList::Core::Settings::self()->autoHideTabBarWithSingleTabItem() );
loadWidget(mTabsHaveCloseButton, MessageList::Core::Settings::self()->tabsHaveCloseButtonItem() );
// "Aggregation":
slotSelectDefaultAggregation();
// "Theme":
slotSelectDefaultTheme();
setDateDisplay( MessageCore::GlobalSettings::self()->dateFormat(),
MessageCore::GlobalSettings::self()->customDateFormat() );
}
void AppearancePage::HeadersTab::setDateDisplay( int num, const QString & format )
{
DateFormatter::FormatType dateDisplay =
static_cast<DateFormatter::FormatType>( num );
// special case: needs text for the line edit:
if ( dateDisplay == DateFormatter::Custom )
mCustomDateFormatEdit->setText( format );
for ( int i = 0 ; i < numDateDisplayConfig ; ++i )
if ( dateDisplay == dateDisplayConfig[i].dateDisplay ) {
mDateDisplay->setSelected( i );
return;
}
// fell through since none found:
mDateDisplay->setSelected( numDateDisplayConfig - 2 ); // default
}
void AppearancePage::HeadersTab::save()
{
saveCheckBox(mDisplayMessageToolTips, MessageList::Core::Settings::self()->messageToolTipEnabledItem());
saveCheckBox(mHideTabBarWithSingleTab, MessageList::Core::Settings::self()->autoHideTabBarWithSingleTabItem() );
saveCheckBox(mTabsHaveCloseButton, MessageList::Core::Settings::self()->tabsHaveCloseButtonItem() );
KMKernel::self()->savePaneSelection();
// "Aggregation"
mAggregationComboBox->writeDefaultConfig();
// "Theme"
mThemeComboBox->writeDefaultConfig();
const int dateDisplayID = mDateDisplay->selected();
// check bounds:
if ( ( dateDisplayID >= 0 ) && ( dateDisplayID < numDateDisplayConfig ) ) {
MessageCore::GlobalSettings::self()->setDateFormat(
static_cast<int>( dateDisplayConfig[ dateDisplayID ].dateDisplay ) );
}
MessageCore::GlobalSettings::self()->setCustomDateFormat( mCustomDateFormatEdit->text() );
}
//
// Message Window
//
QString AppearancePage::ReaderTab::helpAnchor() const
{
return QString::fromLatin1("configure-appearance-reader");
}
AppearancePageReaderTab::AppearancePageReaderTab( QWidget * parent )
: ConfigModuleTab( parent )
{
QVBoxLayout *topLayout = new QVBoxLayout(this);
topLayout->setSpacing( KDialog::spacingHint() );
topLayout->setMargin( KDialog::marginHint() );
// "Close message window after replying or forwarding" check box:
populateCheckBox( mCloseAfterReplyOrForwardCheck = new QCheckBox( this ),
GlobalSettings::self()->closeAfterReplyOrForwardItem() );
mCloseAfterReplyOrForwardCheck->setToolTip(
i18n( "Close the standalone message window after replying or forwarding the message" ) );
topLayout->addWidget( mCloseAfterReplyOrForwardCheck );
connect( mCloseAfterReplyOrForwardCheck, SIGNAL (stateChanged(int)),
this, SLOT(slotEmitChanged()) );
mViewerSettings = new MessageViewer::ConfigureWidget;
connect( mViewerSettings, SIGNAL(settingsChanged()),
this, SLOT(slotEmitChanged()) );
topLayout->addWidget( mViewerSettings );
topLayout->addStretch( 100 ); // spacer
}
void AppearancePage::ReaderTab::doResetToDefaultsOther()
{
}
void AppearancePage::ReaderTab::doLoadOther()
{
loadWidget( mCloseAfterReplyOrForwardCheck, GlobalSettings::self()->closeAfterReplyOrForwardItem() );
mViewerSettings->readConfig();
}
void AppearancePage::ReaderTab::save()
{
saveCheckBox( mCloseAfterReplyOrForwardCheck, GlobalSettings::self()->closeAfterReplyOrForwardItem() );
mViewerSettings->writeConfig();
}
QString AppearancePage::SystemTrayTab::helpAnchor() const
{
return QString::fromLatin1("configure-appearance-systemtray");
}
AppearancePageSystemTrayTab::AppearancePageSystemTrayTab( QWidget * parent )
: ConfigModuleTab( parent )
{
QVBoxLayout * vlay = new QVBoxLayout( this );
vlay->setSpacing( KDialog::spacingHint() );
vlay->setMargin( KDialog::marginHint() );
// "Enable system tray applet" check box
mSystemTrayCheck = new QCheckBox( i18n("Enable system tray icon"), this );
vlay->addWidget( mSystemTrayCheck );
connect( mSystemTrayCheck, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
mSystemTrayShowUnreadMail = new QCheckBox( i18n("Show unread mail in tray icon"), this );
vlay->addWidget( mSystemTrayShowUnreadMail );
mSystemTrayShowUnreadMail->setEnabled(false);
connect( mSystemTrayShowUnreadMail, SIGNAL(stateChanged(int)),
this, SLOT(slotEmitChanged()) );
connect( mSystemTrayCheck, SIGNAL(toggled(bool)),
mSystemTrayShowUnreadMail, SLOT(setEnabled(bool)) );
// System tray modes
mSystemTrayGroup = new KButtonGroup( this );
mSystemTrayGroup->setTitle( i18n("System Tray Mode" ) );
QVBoxLayout *gvlay = new QVBoxLayout( mSystemTrayGroup );
gvlay->setSpacing( KDialog::spacingHint() );
connect( mSystemTrayGroup, SIGNAL(clicked(int)),
this, SLOT(slotEmitChanged()) );
connect( mSystemTrayCheck, SIGNAL(toggled(bool)),
mSystemTrayGroup, SLOT(setEnabled(bool)) );
gvlay->addWidget( new QRadioButton( i18n("Always show KMail in system tray"), mSystemTrayGroup ) );
gvlay->addWidget( new QRadioButton( i18n("Only show KMail in system tray if there are unread messages"), mSystemTrayGroup ) );
vlay->addWidget( mSystemTrayGroup );
vlay->addStretch( 10 ); // spacer
}
void AppearancePage::SystemTrayTab::doLoadFromGlobalSettings()
{
loadWidget(mSystemTrayCheck, GlobalSettings::self()->systemTrayEnabledItem() );
loadWidget(mSystemTrayShowUnreadMail, GlobalSettings::self()->systemTrayShowUnreadItem() );
mSystemTrayGroup->setSelected( GlobalSettings::self()->systemTrayPolicy() );
mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() );
}
void AppearancePage::SystemTrayTab::save()
{
saveCheckBox(mSystemTrayCheck, GlobalSettings::self()->systemTrayEnabledItem() );
GlobalSettings::self()->setSystemTrayPolicy( mSystemTrayGroup->selected() );
saveCheckBox(mSystemTrayShowUnreadMail,GlobalSettings::self()->systemTrayShowUnreadItem());
GlobalSettings::self()->writeConfig();
}
QString AppearancePage::MessageTagTab::helpAnchor() const
{
return QString::fromLatin1("configure-appearance-messagetag");
}
TagListWidgetItem::TagListWidgetItem(QListWidget *parent)
: QListWidgetItem(parent), mTag( 0 )
{
}
TagListWidgetItem::TagListWidgetItem(const QIcon & icon, const QString & text, QListWidget * parent )
: QListWidgetItem(icon, text, parent), mTag( 0 )
{
}
TagListWidgetItem::~TagListWidgetItem()
{
}
void TagListWidgetItem::setKMailTag( const MailCommon::Tag::Ptr& tag )
{
mTag = tag;
}
MailCommon::Tag::Ptr TagListWidgetItem::kmailTag() const
{
return mTag;
}
AppearancePageMessageTagTab::AppearancePageMessageTagTab( QWidget * parent )
: ConfigModuleTab( parent )
{
mPreviousTag = -1;
QHBoxLayout *maingrid = new QHBoxLayout( this );
maingrid->setMargin( KDialog::marginHint() );
maingrid->setSpacing( KDialog::spacingHint() );
//Lefthand side Listbox and friends
//Groupbox frame
mTagsGroupBox = new QGroupBox( i18n("A&vailable Tags"), this );
maingrid->addWidget( mTagsGroupBox );
QVBoxLayout *tageditgrid = new QVBoxLayout( mTagsGroupBox );
tageditgrid->setMargin( KDialog::marginHint() );
tageditgrid->setSpacing( KDialog::spacingHint() );
tageditgrid->addSpacing( 2 * KDialog::spacingHint() );
//Listbox, add, remove row
QHBoxLayout *addremovegrid = new QHBoxLayout();
tageditgrid->addLayout( addremovegrid );
mTagAddLineEdit = new KLineEdit( mTagsGroupBox );
mTagAddLineEdit->setTrapReturnKey( true );
addremovegrid->addWidget( mTagAddLineEdit );
mTagAddButton = new KPushButton( mTagsGroupBox );
mTagAddButton->setToolTip( i18n("Add new tag") );
mTagAddButton->setIcon( KIcon( QLatin1String("list-add") ) );
addremovegrid->addWidget( mTagAddButton );
mTagRemoveButton = new KPushButton( mTagsGroupBox );
mTagRemoveButton->setToolTip( i18n("Remove selected tag") );
mTagRemoveButton->setIcon( KIcon( QLatin1String("list-remove") ) );
addremovegrid->addWidget( mTagRemoveButton );
//Up and down buttons
QHBoxLayout *updowngrid = new QHBoxLayout();
tageditgrid->addLayout( updowngrid );
mTagUpButton = new KPushButton( mTagsGroupBox );
mTagUpButton->setToolTip( i18n("Increase tag priority") );
mTagUpButton->setIcon( KIcon( QLatin1String("arrow-up") ) );
mTagUpButton->setAutoRepeat( true );
updowngrid->addWidget( mTagUpButton );
mTagDownButton = new KPushButton( mTagsGroupBox );
mTagDownButton->setToolTip( i18n("Decrease tag priority") );
mTagDownButton->setIcon( KIcon( QLatin1String("arrow-down") ) );
mTagDownButton->setAutoRepeat( true );
updowngrid->addWidget( mTagDownButton );
//Listbox for tag names
QHBoxLayout *listboxgrid = new QHBoxLayout();
tageditgrid->addLayout( listboxgrid );
mTagListBox = new QListWidget( mTagsGroupBox );
mTagListBox->setDragDropMode(QAbstractItemView::InternalMove);
connect( mTagListBox->model(),SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),SLOT(slotRowsMoved(QModelIndex,int,int,QModelIndex,int)) );
mTagListBox->setMinimumWidth( 150 );
listboxgrid->addWidget( mTagListBox );
//RHS for individual tag settings
//Extra VBoxLayout for stretchers around settings
QVBoxLayout *tagsettinggrid = new QVBoxLayout();
maingrid->addLayout( tagsettinggrid );
//tagsettinggrid->addStretch( 10 );
//Groupbox frame
mTagSettingGroupBox = new QGroupBox( i18n("Ta&g Settings"),
this );
tagsettinggrid->addWidget( mTagSettingGroupBox );
QList<KActionCollection *> actionCollections;
if( kmkernel->getKMMainWidget() )
actionCollections = kmkernel->getKMMainWidget()->actionCollections();
QHBoxLayout *lay = new QHBoxLayout(mTagSettingGroupBox);
mTagWidget = new MailCommon::TagWidget(actionCollections,this);
lay->addWidget(mTagWidget);
connect(mTagWidget,SIGNAL(changed()),this, SLOT(slotEmitChangeCheck()));
//For enabling the add button in case box is non-empty
connect( mTagAddLineEdit, SIGNAL(textChanged(QString)),
this, SLOT(slotAddLineTextChanged(QString)) );
//For on-the-fly updating of tag name in editbox
connect( mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(slotNameLineTextChanged(QString)) );
connect( mTagWidget, SIGNAL(iconNameChanged(QString)), SLOT(slotIconNameChanged(QString)) );
connect( mTagAddLineEdit, SIGNAL(returnPressed()),
this, SLOT(slotAddNewTag()) );
connect( mTagAddButton, SIGNAL(clicked()),
this, SLOT(slotAddNewTag()) );
connect( mTagRemoveButton, SIGNAL(clicked()),
this, SLOT(slotRemoveTag()) );
connect( mTagUpButton, SIGNAL(clicked()),
this, SLOT(slotMoveTagUp()) );
connect( mTagDownButton, SIGNAL(clicked()),
this, SLOT(slotMoveTagDown()) );
connect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
//Adjust widths for columns
maingrid->setStretchFactor( mTagsGroupBox, 1 );
maingrid->setStretchFactor( lay, 1 );
tagsettinggrid->addStretch( 10 );
}
AppearancePageMessageTagTab::~AppearancePageMessageTagTab()
{
}
void AppearancePage::MessageTagTab::slotEmitChangeCheck()
{
slotEmitChanged();
}
void AppearancePage::MessageTagTab::slotRowsMoved( const QModelIndex &,
int sourcestart, int sourceEnd,
const QModelIndex &, int destinationRow )
{
Q_UNUSED( sourceEnd );
Q_UNUSED( sourcestart );
Q_UNUSED( destinationRow );
updateButtons();
slotEmitChangeCheck();
}
void AppearancePage::MessageTagTab::updateButtons()
{
const int currentIndex = mTagListBox->currentRow();
const bool theFirst = ( currentIndex == 0 );
const bool theLast = ( currentIndex >= (int)mTagListBox->count() - 1 );
const bool aFilterIsSelected = ( currentIndex >= 0 );
mTagUpButton->setEnabled( aFilterIsSelected && !theFirst );
mTagDownButton->setEnabled( aFilterIsSelected && !theLast );
}
void AppearancePage::MessageTagTab::slotMoveTagUp()
{
const int tmp_index = mTagListBox->currentRow();
if ( tmp_index <= 0 )
return;
swapTagsInListBox( tmp_index, tmp_index - 1 );
updateButtons();
}
void AppearancePage::MessageTagTab::slotMoveTagDown()
{
const int tmp_index = mTagListBox->currentRow();
if ( ( tmp_index < 0 )
|| ( tmp_index >= int( mTagListBox->count() ) - 1 ) )
return;
swapTagsInListBox( tmp_index, tmp_index + 1 );
updateButtons();
}
void AppearancePage::MessageTagTab::swapTagsInListBox( const int first,
const int second )
{
disconnect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
QListWidgetItem *item = mTagListBox->takeItem( first );
// now selected item is at idx(idx-1), so
// insert the other item at idx, ie. above(below).
mPreviousTag = second;
mTagListBox->insertItem( second, item );
mTagListBox->setCurrentRow( second );
connect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
slotEmitChangeCheck();
}
void AppearancePage::MessageTagTab::slotRecordTagSettings( int aIndex )
{
if ( ( aIndex < 0 ) || ( aIndex >= int( mTagListBox->count() ) ) )
return;
QListWidgetItem *item = mTagListBox->item( aIndex );
TagListWidgetItem *tagItem = static_cast<TagListWidgetItem*>( item );
MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag();
tmp_desc->tagName = tagItem->text();
mTagWidget->recordTagSettings(tmp_desc);
}
void AppearancePage::MessageTagTab::slotUpdateTagSettingWidgets( int aIndex )
{
//Check if selection is valid
if ( ( aIndex < 0 ) || ( mTagListBox->currentRow() < 0 ) ) {
mTagRemoveButton->setEnabled( false );
mTagUpButton->setEnabled( false );
mTagDownButton->setEnabled( false );
mTagWidget->setEnabled(false);
return;
}
mTagWidget->setEnabled(true);
mTagRemoveButton->setEnabled( true );
mTagUpButton->setEnabled( ( 0 != aIndex ) );
mTagDownButton->setEnabled(( ( int( mTagListBox->count() ) - 1 ) != aIndex ) );
QListWidgetItem * item = mTagListBox->currentItem();
TagListWidgetItem *tagItem = static_cast<TagListWidgetItem*>( item );
MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag();
disconnect( mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(slotNameLineTextChanged(QString)) );
mTagWidget->tagNameLineEdit()->setEnabled( !tmp_desc->isImmutable );
mTagWidget->tagNameLineEdit()->setText( tmp_desc->tagName );
connect( mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(slotNameLineTextChanged(QString)) );
mTagWidget->setTagTextColor(tmp_desc->textColor);
mTagWidget->setTagBackgroundColor(tmp_desc->backgroundColor);
mTagWidget->setTagTextFont(tmp_desc->textFont);
mTagWidget->iconButton()->setEnabled( !tmp_desc->isImmutable );
mTagWidget->iconButton()->setIcon( tmp_desc->iconName );
mTagWidget->keySequenceWidget()->setEnabled( true );
mTagWidget->keySequenceWidget()->setKeySequence( tmp_desc->shortcut.primary(),
KKeySequenceWidget::NoValidate );
mTagWidget->inToolBarCheck()->setEnabled( true );
mTagWidget->inToolBarCheck()->setChecked( tmp_desc->inToolbar );
}
void AppearancePage::MessageTagTab::slotSelectionChanged()
{
mEmitChanges = false;
slotRecordTagSettings( mPreviousTag );
slotUpdateTagSettingWidgets( mTagListBox->currentRow() );
mPreviousTag = mTagListBox->currentRow();
mEmitChanges = true;
}
void AppearancePage::MessageTagTab::slotRemoveTag()
{
const int tmp_index = mTagListBox->currentRow();
if ( tmp_index >= 0 ) {
if (KMessageBox::Yes == KMessageBox::questionYesNo(this,i18n("Do you want to remove tag \'%1\'?", mTagListBox->item(mTagListBox->currentRow())->text()))) {
QListWidgetItem * item = mTagListBox->takeItem( mTagListBox->currentRow() );
TagListWidgetItem *tagItem = static_cast<TagListWidgetItem*>( item );
MailCommon::Tag::Ptr tmp_desc = tagItem->kmailTag();
if ( tmp_desc->tag().isValid() ) {
new Akonadi::TagDeleteJob(tmp_desc->tag());
} else {
kWarning() << "Can't remove tag with invalid akonadi tag";
}
mPreviousTag = -1;
//Before deleting the current item, make sure the selectionChanged signal
//is disconnected, so that the widgets will not get updated while the
//deletion takes place.
disconnect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
delete item;
connect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
slotSelectionChanged();
slotEmitChangeCheck();
}
}
}
void AppearancePage::MessageTagTab::slotDeleteTagJob(KJob* job)
{
if (job->error()) {
kWarning() << "Failed to delete tag " << job->errorString();
}
}
void AppearancePage::MessageTagTab::slotNameLineTextChanged( const QString
&aText )
{
//If deleted all, leave the first character for the sake of not having an
//empty tag name
if ( aText.isEmpty() && !mTagListBox->currentItem())
return;
const int count = mTagListBox->count();
for ( int i=0; i < count; ++i ) {
if(mTagListBox->item(i)->text() == aText) {
KMessageBox::error(this,i18n("We cannot create tag. A tag with same name already exists."));
disconnect( mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(slotNameLineTextChanged(QString)) );
mTagWidget->tagNameLineEdit()->setText(mTagListBox->currentItem()->text());
connect( mTagWidget->tagNameLineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(slotNameLineTextChanged(QString)) );
return;
}
}
//Disconnect so the tag information is not saved and reloaded with every
//letter
disconnect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
mTagListBox->currentItem()->setText( aText );
connect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
}
void AppearancePage::MessageTagTab::slotIconNameChanged( const QString &iconName )
{
mTagListBox->currentItem()->setIcon( KIcon( iconName ) );
}
void AppearancePage::MessageTagTab::slotAddLineTextChanged( const QString &aText )
{
mTagAddButton->setEnabled( !aText.trimmed().isEmpty() );
}
void AppearancePage::MessageTagTab::slotAddNewTag()
{
const QString newTagName = mTagAddLineEdit->text();
const int count = mTagListBox->count();
for ( int i=0; i < count; ++i ) {
if(mTagListBox->item(i)->text() == newTagName) {
KMessageBox::error(this,i18n("We cannot create tag. A tag with same name already exists."));
return;
}
}
const int tmp_priority = mTagListBox->count();
MailCommon::Tag::Ptr tag( Tag::createDefaultTag( newTagName ) );
tag->priority = tmp_priority;
slotEmitChangeCheck();
TagListWidgetItem *newItem = new TagListWidgetItem( KIcon( tag->iconName ), newTagName, mTagListBox );
newItem->setKMailTag( tag );
mTagListBox->addItem( newItem );
mTagListBox->setCurrentItem( newItem );
mTagAddLineEdit->setText( QString() );
}
void AppearancePage::MessageTagTab::doLoadFromGlobalSettings()
{
mTagListBox->clear();
Akonadi::TagFetchJob *fetchJob = new Akonadi::TagFetchJob(this);
fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>();
connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(slotTagsFetched(KJob*)));
}
void AppearancePage::MessageTagTab::slotTagsFetched(KJob *job)
{
if (job->error()) {
kWarning() << "Failed to load tags " << job->errorString();
return;
}
Akonadi::TagFetchJob *fetchJob = static_cast<Akonadi::TagFetchJob*>(job);
QList<MailCommon::TagPtr> msgTagList;
foreach( const Akonadi::Tag &akonadiTag, fetchJob->tags() ) {
MailCommon::Tag::Ptr tag = MailCommon::Tag::fromAkonadi( akonadiTag );
msgTagList.append( tag );
}
qSort( msgTagList.begin(), msgTagList.end(), MailCommon::Tag::compare );
foreach( const MailCommon::Tag::Ptr& tag, msgTagList ) {
TagListWidgetItem *newItem = new TagListWidgetItem( KIcon( tag->iconName ), tag->tagName, mTagListBox );
newItem->setKMailTag( tag );
if ( tag->priority == -1 )
tag->priority = mTagListBox->count() - 1;
}
//Disconnect so that insertItem's do not trigger an update procedure
disconnect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
connect( mTagListBox, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(slotSelectionChanged()) );
slotUpdateTagSettingWidgets( -1 );
//Needed since the previous function doesn't affect add button
mTagAddButton->setEnabled( false );
// Save the original list
mOriginalMsgTagList.clear();
foreach( const MailCommon::TagPtr &tag, msgTagList ) {
mOriginalMsgTagList.append( MailCommon::TagPtr( new MailCommon::Tag( *tag ) ) );
}
}
void AppearancePage::MessageTagTab::save()
{
const int currentRow = mTagListBox->currentRow();
if ( currentRow < 0 ) {
return;
}
const int count = mTagListBox->count();
if ( !count ) {
return;
}
QListWidgetItem *item = mTagListBox->currentItem();
if ( !item ) {
return;
}
slotRecordTagSettings( currentRow );
const int numberOfMsgTagList = count;
for ( int i=0; i < numberOfMsgTagList; ++i ) {
TagListWidgetItem *tagItem = static_cast<TagListWidgetItem*>( mTagListBox->item(i) );
if ( ( i>=mOriginalMsgTagList.count() ) || *(tagItem->kmailTag()) != *(mOriginalMsgTagList[i]) ) {
MailCommon::Tag::Ptr tag = tagItem->kmailTag();
tag->priority = i;
MailCommon::Tag::SaveFlags saveFlags = mTagWidget->saveFlags();
Akonadi::Tag akonadiTag = tag->saveToAkonadi( saveFlags );
if ((*tag).id()> 0) {
akonadiTag.setId((*tag).id());
}
if (akonadiTag.isValid()) {
new Akonadi::TagModifyJob(akonadiTag);
} else {
new Akonadi::TagCreateJob(akonadiTag);
}
}
}
}