You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
906 lines
22 KiB
906 lines
22 KiB
/****************************************************************************** |
|
* |
|
* Copyright 2008 Szymon Tomasz Stefanek <pragma@kvirc.net> |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation; either version 2 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* 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 "messagelistview/core/theme.h" |
|
|
|
#include <QDataStream> |
|
|
|
#include <KLocale> |
|
#include <KGlobalSettings> |
|
#include <KDebug> |
|
|
|
namespace KMail |
|
{ |
|
|
|
namespace MessageListView |
|
{ |
|
|
|
namespace Core |
|
{ |
|
|
|
// |
|
// Theme versioning |
|
// |
|
// The themes simply have a DWORD version number attacched. |
|
// The earliest version we're able to load is 0x1013. |
|
// |
|
// Theme revision history: |
|
// |
|
// Version Date introduced Description |
|
// -------------------------------------------------------------------------------------------------------------- |
|
// 0x1013 08.11.2008 Initial theme version, introduced when this piece of code has been moved into trunk. |
|
// 0x1014 12.11.2008 Added runtime column data: width and column visibility |
|
// 0x1015 03.03.2009 Added icon size |
|
// 0x1016 08.03.2009 Added support for sorting by New/Unread status |
|
// |
|
static const int gThemeCurrentVersion = 0x1016; // increase if you add new fields of change the meaning of some |
|
// you don't need to change the values below, but you might want to add new ones |
|
static const int gThemeMinimumSupportedVersion = 0x1013; |
|
static const int gThemeMinimumVersionWithColumnRuntimeData = 0x1014; |
|
static const int gThemeMinimumVersionWithIconSizeField = 0x1015; |
|
static const int gThemeMinimumVersionWithSortingByNewUnreadStatusAllowed = 0x1016; |
|
|
|
// the default icon size |
|
static const int gThemeDefaultIconSize = 16; |
|
|
|
|
|
Theme::ContentItem::ContentItem( Type type ) |
|
: mType( type ), mFlags( 0 ), mLastPaintDevice( 0 ), mFontMetrics( QFont() ) |
|
{ |
|
} |
|
|
|
Theme::ContentItem::ContentItem( const ContentItem &src ) |
|
: mType( src.mType ), |
|
mFlags( src.mFlags ), |
|
mFont( src.mFont ), |
|
mCustomColor( src.mCustomColor ), |
|
mLastPaintDevice( src.mLastPaintDevice ), |
|
mFontMetrics( src.mFontMetrics ), |
|
mLineSpacing( src.mLineSpacing ) |
|
{ |
|
} |
|
|
|
QString Theme::ContentItem::description( Type type ) |
|
{ |
|
switch ( type ) |
|
{ |
|
case Subject: |
|
return i18nc( "Description of Type Subject", "Subject" ); |
|
break; |
|
case Date: |
|
return i18nc( "Description of Type Date", "Date" ); |
|
break; |
|
case SenderOrReceiver: |
|
return i18n( "Sender/Receiver" ); |
|
break; |
|
case Sender: |
|
return i18nc( "Description of Type Sender", "Sender" ); |
|
break; |
|
case Receiver: |
|
return i18nc( "Description of Type Receiver", "Receiver" ); |
|
break; |
|
case Size: |
|
return i18nc( "Description of Type Size", "Size" ); |
|
break; |
|
case ReadStateIcon: |
|
return i18n( "New/Unread/Read Icon" ); |
|
break; |
|
case AttachmentStateIcon: |
|
return i18n( "Attachment Icon" ); |
|
break; |
|
case RepliedStateIcon: |
|
return i18n( "Replied/Forwarded Icon" ); |
|
break; |
|
case CombinedReadRepliedStateIcon: |
|
return i18n( "Combined New/Unread/Read/Replied/Forwarded Icon" ); |
|
break; |
|
case ActionItemStateIcon: |
|
return i18n( "Action Item Icon" ); |
|
break; |
|
case ImportantStateIcon: |
|
return i18n( "Important Icon" ); |
|
break; |
|
case GroupHeaderLabel: |
|
return i18n( "Group Header Label" ); |
|
break; |
|
case SpamHamStateIcon: |
|
return i18n( "Spam/Ham Icon" ); |
|
break; |
|
case WatchedIgnoredStateIcon: |
|
return i18n( "Watched/Ignored Icon" ); |
|
break; |
|
case ExpandedStateIcon: |
|
return i18n( "Group Header Expand/Collapse Icon" ); |
|
break; |
|
case EncryptionStateIcon: |
|
return i18n( "Encryption State Icon" ); |
|
break; |
|
case SignatureStateIcon: |
|
return i18n( "Signature State Icon" ); |
|
break; |
|
case VerticalLine: |
|
return i18n( "Vertical Separation Line" ); |
|
break; |
|
case HorizontalSpacer: |
|
return i18n( "Horizontal Spacer" ); |
|
break; |
|
case MostRecentDate: |
|
return i18n( "Max Date" ); |
|
break; |
|
case TagList: |
|
return i18n( "Message Tags" ); |
|
break; |
|
default: |
|
return i18nc( "Description for an Unknown Type", "Unknown" ); |
|
break; |
|
} |
|
} |
|
|
|
|
|
bool Theme::ContentItem::applicableToMessageItems( Type type ) |
|
{ |
|
return ( static_cast< int >( type ) & ApplicableToMessageItems ); |
|
} |
|
|
|
bool Theme::ContentItem::applicableToGroupHeaderItems( Type type ) |
|
{ |
|
return ( static_cast< int >( type ) & ApplicableToGroupHeaderItems ); |
|
} |
|
|
|
|
|
void Theme::ContentItem::updateFontMetrics( QPaintDevice * device ) |
|
{ |
|
if ( !( mFlags & UseCustomFont ) ) |
|
mFont = KGlobalSettings::generalFont(); |
|
mLastPaintDevice = device; |
|
mFontMetrics = QFontMetrics( mFont, device ); |
|
mLineSpacing = mFontMetrics.lineSpacing(); |
|
} |
|
|
|
void Theme::ContentItem::setFont( const QFont &font ) |
|
{ |
|
mFont = font; |
|
mLastPaintDevice = 0; // will force regeneration of font metrics |
|
} |
|
|
|
void Theme::ContentItem::resetCache() |
|
{ |
|
mLastPaintDevice = 0; // will force regeneration of font metrics |
|
} |
|
|
|
void Theme::ContentItem::save( QDataStream &stream ) const |
|
{ |
|
stream << (int)mType; |
|
stream << mFlags; |
|
stream << mFont; |
|
stream << mCustomColor; |
|
} |
|
|
|
bool Theme::ContentItem::load( QDataStream &stream, int /*themeVersion*/ ) |
|
{ |
|
int val; |
|
|
|
stream >> val; |
|
mType = static_cast< Type >( val ); |
|
switch( mType ) |
|
{ |
|
case Subject: |
|
case Date: |
|
case SenderOrReceiver: |
|
case Sender: |
|
case Receiver: |
|
case Size: |
|
case ReadStateIcon: |
|
case AttachmentStateIcon: |
|
case RepliedStateIcon: |
|
case GroupHeaderLabel: |
|
case ActionItemStateIcon: |
|
case ImportantStateIcon: |
|
case SpamHamStateIcon: |
|
case WatchedIgnoredStateIcon: |
|
case ExpandedStateIcon: |
|
case EncryptionStateIcon: |
|
case SignatureStateIcon: |
|
case VerticalLine: |
|
case HorizontalSpacer: |
|
case MostRecentDate: |
|
case CombinedReadRepliedStateIcon: |
|
case TagList: |
|
// ok |
|
break; |
|
default: |
|
kDebug() << "Invalid content item type"; |
|
return false; // b0rken |
|
break; |
|
} |
|
|
|
stream >> mFlags; |
|
stream >> mFont; |
|
stream >> mCustomColor; |
|
if ( mFlags & UseCustomColor ) |
|
{ |
|
if ( !mCustomColor.isValid() ) |
|
mFlags &= ~UseCustomColor; |
|
} |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
Theme::Row::Row() |
|
{ |
|
} |
|
|
|
Theme::Row::Row( const Row &src ) |
|
{ |
|
for ( QList< ContentItem * >::ConstIterator it = src.mLeftItems.constBegin(); it != src.mLeftItems.constEnd() ; ++it ) |
|
addLeftItem( new ContentItem( *( *it ) ) ); |
|
for ( QList< ContentItem * >::ConstIterator it = src.mRightItems.constBegin(); it != src.mRightItems.constEnd() ; ++it ) |
|
addRightItem( new ContentItem( *( *it ) ) ); |
|
} |
|
|
|
|
|
Theme::Row::~Row() |
|
{ |
|
removeAllLeftItems(); |
|
removeAllRightItems(); |
|
} |
|
|
|
void Theme::Row::removeAllLeftItems() |
|
{ |
|
while( !mLeftItems.isEmpty() ) |
|
delete mLeftItems.takeFirst(); |
|
} |
|
|
|
void Theme::Row::removeAllRightItems() |
|
{ |
|
while( !mRightItems.isEmpty() ) |
|
delete mRightItems.takeFirst(); |
|
} |
|
|
|
void Theme::Row::insertLeftItem( int idx, ContentItem * item ) |
|
{ |
|
if ( idx >= mLeftItems.count() ) |
|
{ |
|
mLeftItems.append( item ); |
|
return; |
|
} |
|
mLeftItems.insert( idx, item ); |
|
} |
|
|
|
void Theme::Row::insertRightItem( int idx, ContentItem * item ) |
|
{ |
|
if ( idx >= mRightItems.count() ) |
|
{ |
|
mRightItems.append( item ); |
|
return; |
|
} |
|
mRightItems.insert( idx, item ); |
|
} |
|
|
|
void Theme::Row::resetCache() |
|
{ |
|
mSizeHint = QSize(); |
|
for ( QList< ContentItem * >::ConstIterator it = mLeftItems.constBegin(); it != mLeftItems.constEnd() ; ++it ) |
|
( *it )->resetCache(); |
|
for ( QList< ContentItem * >::ConstIterator it = mRightItems.constBegin(); it != mRightItems.constEnd() ; ++it ) |
|
( *it )->resetCache(); |
|
} |
|
|
|
bool Theme::Row::containsTextItems() const |
|
{ |
|
for ( QList< ContentItem * >::ConstIterator it = mLeftItems.constBegin(); it != mLeftItems.constEnd() ; ++it ) |
|
{ |
|
if ( ( *it )->displaysText() ) |
|
return true; |
|
} |
|
for ( QList< ContentItem * >::ConstIterator it = mRightItems.constBegin(); it != mRightItems.constEnd() ; ++it ) |
|
{ |
|
if ( ( *it )->displaysText() ) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
void Theme::Row::save( QDataStream &stream ) const |
|
{ |
|
stream << (int)mLeftItems.count(); |
|
|
|
int cnt = mLeftItems.count(); |
|
|
|
for ( int i = 0; i < cnt ; ++i ) |
|
{ |
|
ContentItem * ci = mLeftItems.at( i ); |
|
ci->save( stream ); |
|
} |
|
|
|
stream << (int)mRightItems.count(); |
|
|
|
cnt = mRightItems.count(); |
|
|
|
for ( int i = 0; i < cnt ; ++i ) |
|
{ |
|
ContentItem * ci = mRightItems.at( i ); |
|
ci->save( stream ); |
|
} |
|
} |
|
|
|
bool Theme::Row::load( QDataStream &stream, int themeVersion ) |
|
{ |
|
removeAllLeftItems(); |
|
removeAllRightItems(); |
|
|
|
int val; |
|
|
|
// left item count |
|
|
|
stream >> val; |
|
|
|
if ( ( val < 0 ) || ( val > 50 ) ) |
|
return false; // senseless |
|
|
|
for ( int i = 0; i < val ; ++i ) |
|
{ |
|
ContentItem * ci = new ContentItem( ContentItem::Subject ); // dummy type |
|
if ( !ci->load( stream, themeVersion ) ) |
|
{ |
|
kDebug() << "Left content item loading failed"; |
|
delete ci; |
|
return false; |
|
} |
|
addLeftItem( ci ); |
|
} |
|
|
|
// right item count |
|
|
|
stream >> val; |
|
|
|
if ( ( val < 0 ) || ( val > 50 ) ) |
|
return false; // senseless |
|
|
|
for ( int i = 0; i < val ; ++i ) |
|
{ |
|
ContentItem * ci = new ContentItem( ContentItem::Subject ); // dummy type |
|
if ( !ci->load( stream, themeVersion ) ) |
|
{ |
|
kDebug() << "Right content item loading failed"; |
|
delete ci; |
|
return false; |
|
} |
|
addRightItem( ci ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
Theme::Column::SharedRuntimeData::SharedRuntimeData( bool currentlyVisible, int currentWidth ) |
|
: mReferences( 0 ), mCurrentlyVisible( currentlyVisible ), mCurrentWidth( currentWidth ) |
|
{ |
|
} |
|
|
|
Theme::Column::SharedRuntimeData::~SharedRuntimeData() |
|
{ |
|
} |
|
|
|
void Theme::Column::SharedRuntimeData::addReference() |
|
{ |
|
mReferences++; |
|
} |
|
|
|
bool Theme::Column::SharedRuntimeData::deleteReference() |
|
{ |
|
mReferences--; |
|
Q_ASSERT( mReferences >= 0 ); |
|
return mReferences > 0; |
|
} |
|
|
|
void Theme::Column::SharedRuntimeData::save( QDataStream &stream ) const |
|
{ |
|
stream << mCurrentlyVisible; |
|
stream << mCurrentWidth; |
|
} |
|
|
|
bool Theme::Column::SharedRuntimeData::load( QDataStream &stream, int /* themeVersion */ ) |
|
{ |
|
stream >> mCurrentlyVisible; |
|
stream >> mCurrentWidth; |
|
if ( mCurrentWidth > 10000 ) |
|
{ |
|
kDebug() << "Theme has insane column width " << mCurrentWidth << " chopping to 100"; |
|
mCurrentWidth = 100; // avoid really insane values |
|
} |
|
return (mCurrentWidth >= -1); |
|
} |
|
|
|
|
|
Theme::Column::Column() |
|
: mVisibleByDefault( true ), |
|
mIsSenderOrReceiver( false ), |
|
mMessageSorting( SortOrder::NoMessageSorting ) |
|
{ |
|
mSharedRuntimeData = new SharedRuntimeData( true, -1 ); |
|
mSharedRuntimeData->addReference(); |
|
} |
|
|
|
Theme::Column::Column( const Column &src ) |
|
{ |
|
mLabel = src.mLabel; |
|
mVisibleByDefault = src.mVisibleByDefault; |
|
mIsSenderOrReceiver = src.mIsSenderOrReceiver; |
|
mMessageSorting = src.mMessageSorting; |
|
|
|
mSharedRuntimeData = src.mSharedRuntimeData; |
|
mSharedRuntimeData->addReference(); |
|
|
|
for ( QList< Row * >::ConstIterator it = src.mMessageRows.constBegin(); it != src.mMessageRows.constEnd() ; ++it ) |
|
addMessageRow( new Row( *( *it ) ) ); |
|
for ( QList< Row * >::ConstIterator it = src.mGroupHeaderRows.constBegin(); it != src.mGroupHeaderRows.constEnd() ; ++it ) |
|
addGroupHeaderRow( new Row( *( *it ) ) ); |
|
} |
|
|
|
Theme::Column::~Column() |
|
{ |
|
removeAllMessageRows(); |
|
removeAllGroupHeaderRows(); |
|
if( !( mSharedRuntimeData->deleteReference() ) ) |
|
delete mSharedRuntimeData; |
|
} |
|
|
|
void Theme::Column::detach() |
|
{ |
|
if( mSharedRuntimeData->referenceCount() < 2 ) |
|
return; // nothing to detach |
|
mSharedRuntimeData->deleteReference(); |
|
|
|
mSharedRuntimeData = new SharedRuntimeData( mVisibleByDefault, -1 ); |
|
mSharedRuntimeData->addReference(); |
|
|
|
} |
|
|
|
void Theme::Column::removeAllMessageRows() |
|
{ |
|
while ( !mMessageRows.isEmpty() ) |
|
delete mMessageRows.takeFirst(); |
|
} |
|
|
|
void Theme::Column::removeAllGroupHeaderRows() |
|
{ |
|
while ( !mGroupHeaderRows.isEmpty() ) |
|
delete mGroupHeaderRows.takeFirst(); |
|
} |
|
|
|
void Theme::Column::insertMessageRow( int idx, Row * row ) |
|
{ |
|
if ( idx >= mMessageRows.count() ) |
|
{ |
|
mMessageRows.append( row ); |
|
return; |
|
} |
|
mMessageRows.insert( idx, row ); |
|
} |
|
|
|
void Theme::Column::insertGroupHeaderRow( int idx, Row * row ) |
|
{ |
|
if ( idx >= mGroupHeaderRows.count() ) |
|
{ |
|
mGroupHeaderRows.append( row ); |
|
return; |
|
} |
|
mGroupHeaderRows.insert( idx, row ); |
|
} |
|
|
|
void Theme::Column::resetCache() |
|
{ |
|
mGroupHeaderSizeHint = QSize(); |
|
mMessageSizeHint = QSize(); |
|
|
|
for ( QList< Row * >::ConstIterator it = mMessageRows.constBegin(); it != mMessageRows.constEnd() ; ++it ) |
|
( *it )->resetCache(); |
|
for ( QList< Row * >::ConstIterator it = mGroupHeaderRows.constBegin(); it != mGroupHeaderRows.constEnd() ; ++it ) |
|
( *it )->resetCache(); |
|
} |
|
|
|
bool Theme::Column::containsTextItems() const |
|
{ |
|
for ( QList< Row * >::ConstIterator it = mMessageRows.constBegin(); it != mMessageRows.constEnd() ; ++it ) |
|
{ |
|
if ( ( *it )->containsTextItems() ) |
|
return true; |
|
} |
|
for ( QList< Row * >::ConstIterator it = mGroupHeaderRows.constBegin(); it != mGroupHeaderRows.constEnd() ; ++it ) |
|
{ |
|
if ( ( *it )->containsTextItems() ) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
void Theme::Column::save( QDataStream &stream ) const |
|
{ |
|
stream << mLabel; |
|
stream << mVisibleByDefault; |
|
stream << mIsSenderOrReceiver; |
|
stream << (int)mMessageSorting; |
|
|
|
stream << (int)mGroupHeaderRows.count(); |
|
|
|
int cnt = mGroupHeaderRows.count(); |
|
|
|
for ( int i = 0; i < cnt ; ++i ) |
|
{ |
|
Row * row = mGroupHeaderRows.at( i ); |
|
row->save( stream ); |
|
} |
|
|
|
stream << (int)mMessageRows.count(); |
|
|
|
cnt = mMessageRows.count(); |
|
|
|
for ( int i = 0; i < cnt ; ++i ) |
|
{ |
|
Row * row = mMessageRows.at( i ); |
|
row->save( stream ); |
|
} |
|
|
|
// added in version 0x1014 |
|
mSharedRuntimeData->save( stream ); |
|
|
|
} |
|
|
|
bool Theme::Column::load( QDataStream &stream, int themeVersion ) |
|
{ |
|
removeAllGroupHeaderRows(); |
|
removeAllMessageRows(); |
|
|
|
stream >> mLabel; |
|
stream >> mVisibleByDefault; |
|
stream >> mIsSenderOrReceiver; |
|
|
|
int val; |
|
|
|
stream >> val; |
|
mMessageSorting = static_cast< SortOrder::MessageSorting >( val ); |
|
if ( !SortOrder::isValidMessageSorting( mMessageSorting ) ) |
|
{ |
|
kDebug() << "Invalid message sorting"; |
|
return false; |
|
} |
|
|
|
if ( themeVersion < gThemeMinimumVersionWithSortingByNewUnreadStatusAllowed ) |
|
{ |
|
// The default "Classic" theme "New/Unread" column had sorting disabled here. |
|
// We want to be nice to the existing users and automatically set |
|
// the new sorting method for this column (so they don't have to make the |
|
// complex steps to set it by themselves). |
|
// This piece of code isn't strictly required: it's just a niceness :) |
|
if ( ( mMessageSorting == SortOrder::NoMessageSorting ) && ( mLabel == i18n( "New/Unread" ) ) ) |
|
mMessageSorting = SortOrder::SortMessagesByNewUnreadStatus; |
|
} |
|
|
|
// group header row count |
|
stream >> val; |
|
|
|
if ( ( val < 0 ) || ( val > 50 ) ) |
|
{ |
|
kDebug() << "Invalid group header row count"; |
|
return false; // senseless |
|
} |
|
|
|
for ( int i = 0; i < val ; i++ ) |
|
{ |
|
Row * row = new Row(); |
|
if ( !row->load( stream, themeVersion ) ) |
|
{ |
|
kDebug() << "Group header row loading failed"; |
|
delete row; |
|
return false; |
|
} |
|
addGroupHeaderRow( row ); |
|
} |
|
|
|
// message row count |
|
stream >> val; |
|
|
|
if ( ( val < 0 ) || ( val > 50 ) ) |
|
{ |
|
kDebug() << "Invalid message row count"; |
|
return false; // senseless |
|
} |
|
|
|
for ( int i = 0; i < val ; i++ ) |
|
{ |
|
Row * row = new Row(); |
|
if ( !row->load( stream, themeVersion ) ) |
|
{ |
|
kDebug() << "Message row loading failed"; |
|
delete row; |
|
return false; |
|
} |
|
addMessageRow( row ); |
|
} |
|
|
|
if ( themeVersion >= gThemeMinimumVersionWithColumnRuntimeData ) |
|
{ |
|
// starting with version 0x1014 we have runtime data too |
|
if( !mSharedRuntimeData->load( stream, themeVersion ) ) |
|
{ |
|
kDebug() << "Shared runtime data loading failed"; |
|
return false; |
|
} |
|
} else { |
|
// assume default shared data |
|
mSharedRuntimeData->setCurrentlyVisible( mVisibleByDefault ); |
|
mSharedRuntimeData->setCurrentWidth( -1 ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
Theme::Theme() |
|
: OptionSet() |
|
{ |
|
mGroupHeaderBackgroundMode = AutoColor; |
|
mViewHeaderPolicy = ShowHeaderAlways; |
|
mIconSize = gThemeDefaultIconSize; |
|
} |
|
|
|
Theme::Theme( const QString &name, const QString &description ) |
|
: OptionSet( name, description ) |
|
{ |
|
mGroupHeaderBackgroundMode = AutoColor; |
|
mGroupHeaderBackgroundStyle = StyledJoinedRect; |
|
mViewHeaderPolicy = ShowHeaderAlways; |
|
mIconSize = gThemeDefaultIconSize; |
|
} |
|
|
|
|
|
Theme::Theme( const Theme &src ) |
|
: OptionSet( src ) |
|
{ |
|
mGroupHeaderBackgroundMode = src.mGroupHeaderBackgroundMode; |
|
mGroupHeaderBackgroundColor = src.mGroupHeaderBackgroundColor; |
|
mGroupHeaderBackgroundStyle = src.mGroupHeaderBackgroundStyle; |
|
mViewHeaderPolicy = src.mViewHeaderPolicy; |
|
mIconSize = src.mIconSize; |
|
|
|
for ( QList< Column * >::ConstIterator it = src.mColumns.constBegin(); it != src.mColumns.constEnd() ; ++it ) |
|
addColumn( new Column( *( *it ) ) ); |
|
} |
|
|
|
Theme::~Theme() |
|
{ |
|
removeAllColumns(); |
|
} |
|
|
|
void Theme::detach() |
|
{ |
|
for ( QList< Column * >::Iterator it = mColumns.begin(); it != mColumns.end() ; ++it ) |
|
( *it )->detach(); |
|
} |
|
|
|
void Theme::resetColumnState() |
|
{ |
|
for ( QList< Column * >::Iterator it = mColumns.begin(); it != mColumns.end() ; ++it ) |
|
{ |
|
( *it )->setCurrentlyVisible( ( *it )->visibleByDefault() ); |
|
( *it )->setCurrentWidth( -1 ); |
|
} |
|
} |
|
|
|
void Theme::resetColumnSizes() |
|
{ |
|
for ( QList< Column * >::Iterator it = mColumns.begin(); it != mColumns.end() ; ++it ) |
|
( *it )->setCurrentWidth( -1 ); |
|
} |
|
|
|
|
|
void Theme::removeAllColumns() |
|
{ |
|
while ( !mColumns.isEmpty() ) |
|
delete mColumns.takeFirst(); |
|
} |
|
|
|
void Theme::insertColumn( int idx, Column * column ) |
|
{ |
|
if ( idx >= mColumns.count() ) |
|
{ |
|
mColumns.append( column ); |
|
return; |
|
} |
|
mColumns.insert( idx, column ); |
|
} |
|
|
|
void Theme::setGroupHeaderBackgroundMode( GroupHeaderBackgroundMode bm ) |
|
{ |
|
mGroupHeaderBackgroundMode = bm; |
|
if ( ( bm == CustomColor ) && !mGroupHeaderBackgroundColor.isValid() ) |
|
mGroupHeaderBackgroundColor = QColor( 127, 127, 127 ); // something neutral |
|
} |
|
|
|
QList< QPair< QString, int > > Theme::enumerateViewHeaderPolicyOptions() |
|
{ |
|
QList< QPair< QString, int > > ret; |
|
ret.append( QPair< QString, int >( i18n( "Never Show" ), NeverShowHeader ) ); |
|
ret.append( QPair< QString, int >( i18n( "Always Show" ), ShowHeaderAlways ) ); |
|
return ret; |
|
} |
|
|
|
QList< QPair< QString, int > > Theme::enumerateGroupHeaderBackgroundStyles() |
|
{ |
|
QList< QPair< QString, int > > ret; |
|
ret.append( QPair< QString, int >( i18n( "Plain Rectangles" ), PlainRect ) ); |
|
ret.append( QPair< QString, int >( i18n( "Plain Joined Rectangle" ), PlainJoinedRect ) ); |
|
ret.append( QPair< QString, int >( i18n( "Rounded Rectangles" ), RoundedRect ) ); |
|
ret.append( QPair< QString, int >( i18n( "Rounded Joined Rectangle" ), RoundedJoinedRect ) ); |
|
ret.append( QPair< QString, int >( i18n( "Gradient Rectangles" ), GradientRect ) ); |
|
ret.append( QPair< QString, int >( i18n( "Gradient Joined Rectangle" ), GradientJoinedRect ) ); |
|
ret.append( QPair< QString, int >( i18n( "Styled Rectangles" ), StyledRect ) ); |
|
ret.append( QPair< QString, int >( i18n( "Styled Joined Rectangles" ), StyledJoinedRect ) ); |
|
|
|
return ret; |
|
} |
|
|
|
void Theme::setIconSize( int iconSize ) |
|
{ |
|
mIconSize = iconSize; |
|
if ( ( mIconSize < 8 ) || ( mIconSize > 64 ) ) |
|
mIconSize = gThemeDefaultIconSize; |
|
} |
|
|
|
void Theme::resetCache() |
|
{ |
|
for ( QList< Column * >::ConstIterator it = mColumns.constBegin(); it != mColumns.constEnd() ; ++it ) |
|
( *it )->resetCache(); |
|
} |
|
|
|
bool Theme::load( QDataStream &stream ) |
|
{ |
|
removeAllColumns(); |
|
|
|
int themeVersion; |
|
|
|
stream >> themeVersion; |
|
|
|
// We support themes starting at version gThemeMinimumSupportedVersion (0x1013 actually) |
|
|
|
if ( |
|
( themeVersion > gThemeCurrentVersion ) || |
|
( themeVersion < gThemeMinimumSupportedVersion ) |
|
) |
|
{ |
|
kDebug() << "Invalid theme version"; |
|
return false; // b0rken (invalid version) |
|
} |
|
|
|
int val; |
|
|
|
stream >> val; |
|
mGroupHeaderBackgroundMode = (GroupHeaderBackgroundMode)val; |
|
switch(mGroupHeaderBackgroundMode) |
|
{ |
|
case Transparent: |
|
case AutoColor: |
|
case CustomColor: |
|
// ok |
|
break; |
|
default: |
|
kDebug() << "Invalid theme group header background mode"; |
|
return false; // b0rken |
|
break; |
|
} |
|
|
|
stream >> mGroupHeaderBackgroundColor; |
|
|
|
stream >> val; |
|
mGroupHeaderBackgroundStyle = (GroupHeaderBackgroundStyle)val; |
|
switch(mGroupHeaderBackgroundStyle) |
|
{ |
|
case PlainRect: |
|
case PlainJoinedRect: |
|
case RoundedRect: |
|
case RoundedJoinedRect: |
|
case GradientRect: |
|
case GradientJoinedRect: |
|
case StyledRect: |
|
case StyledJoinedRect: |
|
// ok |
|
break; |
|
default: |
|
kDebug() << "Invalid theme group header background style"; |
|
return false; // b0rken |
|
break; |
|
} |
|
|
|
stream >> val; |
|
mViewHeaderPolicy = (ViewHeaderPolicy)val; |
|
switch(mViewHeaderPolicy) |
|
{ |
|
case ShowHeaderAlways: |
|
case NeverShowHeader: |
|
// ok |
|
break; |
|
default: |
|
kDebug() << "Invalid theme view header policy"; |
|
return false; // b0rken |
|
break; |
|
} |
|
|
|
if ( themeVersion >= gThemeMinimumVersionWithIconSizeField ) |
|
{ |
|
// icon size parameter |
|
stream >> mIconSize; |
|
if ( ( mIconSize < 8 ) || ( mIconSize > 64 ) ) |
|
mIconSize = gThemeDefaultIconSize; // limit insane values |
|
} else { |
|
mIconSize = gThemeDefaultIconSize; |
|
} |
|
|
|
// column count |
|
stream >> val; |
|
if ( val < 1 || val > 50 ) |
|
return false; // plain b0rken ( negative, zero or more than 50 columns ) |
|
|
|
for ( int i = 0; i < val ; i++ ) |
|
{ |
|
Column * col = new Column(); |
|
if ( !col->load( stream, themeVersion ) ) |
|
{ |
|
kDebug() << "Column loading failed"; |
|
delete col; |
|
return false; |
|
} |
|
addColumn( col ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void Theme::save( QDataStream &stream ) const |
|
{ |
|
stream << (int)gThemeCurrentVersion; |
|
|
|
stream << (int)mGroupHeaderBackgroundMode; |
|
stream << mGroupHeaderBackgroundColor; |
|
stream << (int)mGroupHeaderBackgroundStyle; |
|
stream << (int)mViewHeaderPolicy; |
|
stream << mIconSize; |
|
|
|
stream << (int)mColumns.count(); |
|
|
|
int cnt = mColumns.count(); |
|
|
|
for ( int i = 0; i < cnt ; i++ ) |
|
{ |
|
Column * col = mColumns.at( i ); |
|
col->save( stream ); |
|
} |
|
} |
|
|
|
} // namespace Core |
|
|
|
} // namespace MessageListView |
|
|
|
} // namespace KMail |
|
|
|
|