akonadi
collectionstatisticsdelegate.cpp
00001 /* 00002 Copyright (c) 2008 Thomas McGuire <thomas.mcguire@gmx.net> 00003 Copyright (c) 2012 Laurent Montel <montel@kde.org> 00004 00005 This library is free software; you can redistribute it and/or modify it 00006 under the terms of the GNU Library General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or (at your 00008 option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, but WITHOUT 00011 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to the 00017 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00018 02110-1301, USA. 00019 */ 00020 00021 #include "collectionstatisticsdelegate.h" 00022 #include "collectionstatisticsmodel.h" 00023 00024 #include <kcolorscheme.h> 00025 #include <kdebug.h> 00026 #include <kio/global.h> 00027 00028 #include <QtGui/QPainter> 00029 #include <QtGui/QStyle> 00030 #include <QtGui/QStyleOption> 00031 #include <QtGui/QStyleOptionViewItemV4> 00032 #include <QtGui/QAbstractItemView> 00033 #include <QtGui/QTreeView> 00034 00035 #include "entitytreemodel.h" 00036 #include "collectionstatistics.h" 00037 #include "collection.h" 00038 #include "progressspinnerdelegate_p.h" 00039 00040 using namespace Akonadi; 00041 00042 namespace Akonadi { 00043 00044 enum CountType 00045 { 00046 UnreadCount, 00047 TotalCount 00048 }; 00049 00050 class CollectionStatisticsDelegatePrivate 00051 { 00052 public: 00053 QAbstractItemView *parent; 00054 bool drawUnreadAfterFolder; 00055 DelegateAnimator *animator; 00056 QColor mSelectedUnreadColor; 00057 QColor mDeselectedUnreadColor; 00058 00059 CollectionStatisticsDelegatePrivate( QAbstractItemView *treeView ) 00060 : parent( treeView ), 00061 drawUnreadAfterFolder( false ), 00062 animator( 0 ) 00063 { 00064 mSelectedUnreadColor = KColorScheme( QPalette::Active, KColorScheme::Selection ) 00065 .foreground( KColorScheme::LinkText ).color(); 00066 mDeselectedUnreadColor = KColorScheme( QPalette::Active, KColorScheme::View ) 00067 .foreground( KColorScheme::LinkText ).color(); 00068 } 00069 00070 void getCountRecursive( const QModelIndex &index, qint64 &totalCount, qint64 &unreadCount, qint64 &totalSize ) const 00071 { 00072 Collection collection = qvariant_cast<Collection>( index.data( EntityTreeModel::CollectionRole ) ); 00073 // Do not assert on invalid collections, since a collection may be deleted 00074 // in the meantime and deleted collections are invalid. 00075 if ( collection.isValid() ) { 00076 CollectionStatistics statistics = collection.statistics(); 00077 totalCount += qMax( 0LL, statistics.count() ); 00078 unreadCount += qMax( 0LL, statistics.unreadCount() ); 00079 totalSize += qMax( 0LL, statistics.size() ); 00080 if ( index.model()->hasChildren( index ) ) { 00081 const int rowCount = index.model()->rowCount( index ); 00082 for ( int row = 0; row < rowCount; row++ ) { 00083 static const int column = 0; 00084 getCountRecursive( index.model()->index( row, column, index ), totalCount, unreadCount, totalSize ); 00085 } 00086 } 00087 } 00088 } 00089 }; 00090 00091 } 00092 00093 CollectionStatisticsDelegate::CollectionStatisticsDelegate( QAbstractItemView *parent ) 00094 : QStyledItemDelegate( parent ), 00095 d_ptr( new CollectionStatisticsDelegatePrivate( parent ) ) 00096 { 00097 00098 } 00099 00100 CollectionStatisticsDelegate::CollectionStatisticsDelegate( QTreeView *parent ) 00101 : QStyledItemDelegate( parent ), 00102 d_ptr( new CollectionStatisticsDelegatePrivate( parent ) ) 00103 { 00104 00105 } 00106 00107 CollectionStatisticsDelegate::~CollectionStatisticsDelegate() 00108 { 00109 delete d_ptr; 00110 } 00111 00112 void CollectionStatisticsDelegate::setUnreadCountShown( bool enable ) 00113 { 00114 Q_D( CollectionStatisticsDelegate ); 00115 d->drawUnreadAfterFolder = enable; 00116 } 00117 00118 bool CollectionStatisticsDelegate::unreadCountShown() const 00119 { 00120 Q_D( const CollectionStatisticsDelegate ); 00121 return d->drawUnreadAfterFolder; 00122 } 00123 00124 void CollectionStatisticsDelegate::setProgressAnimationEnabled( bool enable ) 00125 { 00126 Q_D( CollectionStatisticsDelegate ); 00127 if ( enable == ( d->animator != 0 ) ) 00128 return; 00129 if ( enable ) { 00130 Q_ASSERT( !d->animator ); 00131 Akonadi::DelegateAnimator *animator = new Akonadi::DelegateAnimator( d->parent ); 00132 d->animator = animator; 00133 } else { 00134 delete d->animator; 00135 d->animator = 0; 00136 } 00137 } 00138 00139 bool CollectionStatisticsDelegate::progressAnimationEnabled() const 00140 { 00141 Q_D( const CollectionStatisticsDelegate ); 00142 return d->animator != 0; 00143 } 00144 00145 void CollectionStatisticsDelegate::initStyleOption( QStyleOptionViewItem *option, 00146 const QModelIndex &index ) const 00147 { 00148 Q_D( const CollectionStatisticsDelegate ); 00149 00150 QStyleOptionViewItemV4 *noTextOption = 00151 qstyleoption_cast<QStyleOptionViewItemV4 *>( option ); 00152 QStyledItemDelegate::initStyleOption( noTextOption, index ); 00153 if ( option->decorationPosition != QStyleOptionViewItem::Top ) { 00154 noTextOption->text.clear(); 00155 } 00156 00157 if ( d->animator ) { 00158 00159 const Akonadi::Collection collection = index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>(); 00160 00161 if (!collection.isValid()) 00162 { 00163 d->animator->pop(index); 00164 return; 00165 } 00166 00167 if (index.data(Akonadi::EntityTreeModel::FetchStateRole).toInt() != Akonadi::EntityTreeModel::FetchingState) 00168 { 00169 d->animator->pop(index); 00170 return; 00171 } 00172 00173 d->animator->push(index); 00174 00175 if (QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>(option)) { 00176 v4->icon = d->animator->sequenceFrame(index); 00177 } 00178 } 00179 } 00180 00181 class PainterStateSaver 00182 { 00183 public: 00184 PainterStateSaver( QPainter *painter ) 00185 { 00186 mPainter = painter; 00187 mPainter->save(); 00188 } 00189 00190 ~PainterStateSaver() 00191 { 00192 mPainter->restore(); 00193 } 00194 00195 private: 00196 QPainter *mPainter; 00197 }; 00198 00199 void CollectionStatisticsDelegate::paint( QPainter *painter, 00200 const QStyleOptionViewItem &option, 00201 const QModelIndex &index ) const 00202 { 00203 Q_D( const CollectionStatisticsDelegate ); 00204 PainterStateSaver stateSaver( painter ); 00205 00206 const QColor textColor = index.data( Qt::ForegroundRole ).value<QColor>(); 00207 // First, paint the basic, but without the text. We remove the text 00208 // in initStyleOption(), which gets called by QStyledItemDelegate::paint(). 00209 QStyledItemDelegate::paint( painter, option, index ); 00210 00211 // No, we retrieve the correct style option by calling intiStyleOption from 00212 // the superclass. 00213 QStyleOptionViewItemV4 option4 = option; 00214 QStyledItemDelegate::initStyleOption( &option4, index ); 00215 QString text = option4.text; 00216 00217 // Now calculate the rectangle for the text 00218 QStyle *s = d->parent->style(); 00219 const QWidget *widget = option4.widget; 00220 const QRect textRect = s->subElementRect( QStyle::SE_ItemViewItemText, &option4, widget ); 00221 const QRect iconRect = s->subElementRect( QStyle::SE_ItemViewItemDecoration, &option4, widget ); 00222 00223 // When checking if the item is expanded, we need to check that for the first 00224 // column, as Qt only recogises the index as expanded for the first column 00225 QModelIndex firstColumn = index.model()->index( index.row(), 0, index.parent() ); 00226 QTreeView* treeView = qobject_cast<QTreeView*>( d->parent ); 00227 bool expanded = treeView && treeView->isExpanded( firstColumn ); 00228 00229 if ( option.state & QStyle::State_Selected ) { 00230 painter->setPen( textColor.isValid() ? textColor : option.palette.highlightedText().color() ); 00231 } 00232 00233 Collection collection = index.sibling( index.row(), 0 ).data( EntityTreeModel::CollectionRole ).value<Collection>(); 00234 00235 Q_ASSERT(collection.isValid()); 00236 00237 CollectionStatistics statistics = collection.statistics(); 00238 00239 qint64 unreadCount = qMax( 0LL, statistics.unreadCount() ); 00240 qint64 totalRecursiveCount = 0; 00241 qint64 unreadRecursiveCount = 0; 00242 qint64 totalSize = 0; 00243 d->getCountRecursive( index.sibling( index.row(), 0 ), totalRecursiveCount, unreadRecursiveCount, totalSize ); 00244 00245 // Draw the unread count after the folder name (in parenthesis) 00246 if ( d->drawUnreadAfterFolder && index.column() == 0 ) { 00247 // Construct the string which will appear after the foldername (with the 00248 // unread count) 00249 QString unread; 00250 // qDebug() << expanded << unreadCount << unreadRecursiveCount; 00251 if ( expanded && unreadCount > 0 ) 00252 unread = QString::fromLatin1( " (%1)" ).arg( unreadCount ); 00253 else if ( !expanded ) { 00254 if ( unreadCount != unreadRecursiveCount ) 00255 unread = QString::fromLatin1( " (%1 + %2)" ).arg( unreadCount ).arg( unreadRecursiveCount - unreadCount ); 00256 else if ( unreadCount > 0 ) 00257 unread = QString::fromLatin1( " (%1)" ).arg( unreadCount ); 00258 } 00259 00260 PainterStateSaver stateSaver( painter ); 00261 00262 if ( !unread.isEmpty() ) { 00263 QFont font = painter->font(); 00264 font.setBold( true ); 00265 painter->setFont( font ); 00266 } 00267 00268 const QColor unreadColor = (option.state & QStyle::State_Selected) ? d->mSelectedUnreadColor : d->mDeselectedUnreadColor; 00269 const QRect iconRect = s->subElementRect( QStyle::SE_ItemViewItemDecoration, &option4, widget ); 00270 00271 if ( option.decorationPosition == QStyleOptionViewItem::Left 00272 || option.decorationPosition == QStyleOptionViewItem::Right ) { 00273 // Squeeze the folder text if it is to big and calculate the rectangles 00274 // where the folder text and the unread count will be drawn to 00275 QString folderName = text; 00276 QFontMetrics fm( painter->fontMetrics() ); 00277 const int unreadWidth = fm.width( unread ); 00278 int folderWidth( fm.width( folderName ) ); 00279 const bool enoughPlaceForText = ( option.rect.width() > ( folderWidth + unreadWidth + iconRect.width() ) ); 00280 00281 if ( !enoughPlaceForText && ( folderWidth + unreadWidth > textRect.width() )) { 00282 folderName = fm.elidedText( folderName, Qt::ElideRight, 00283 option.rect.width() - unreadWidth - iconRect.width() ); 00284 folderWidth = fm.width( folderName ); 00285 } 00286 QRect folderRect = textRect; 00287 QRect unreadRect = textRect; 00288 folderRect.setRight( textRect.left() + folderWidth ); 00289 unreadRect = QRect( folderRect.right(), folderRect.top(), unreadRect.width(), unreadRect.height() ); 00290 if ( textColor.isValid() ) 00291 painter->setPen( textColor ); 00292 00293 // Draw folder name and unread count 00294 painter->drawText( folderRect, Qt::AlignLeft | Qt::AlignVCenter, folderName ); 00295 painter->setPen( unreadColor ); 00296 painter->drawText( unreadRect, Qt::AlignLeft | Qt::AlignVCenter, unread ); 00297 } else if ( option.decorationPosition == QStyleOptionViewItem::Top ) { 00298 if ( unreadCount > 0 ) { 00299 // draw over the icon 00300 painter->setPen( unreadColor ); 00301 painter->drawText( iconRect, Qt::AlignCenter, QString::number( unreadCount ) ); 00302 } 00303 } 00304 return; 00305 } 00306 00307 // For the unread/total column, paint the summed up count if the item 00308 // is collapsed 00309 if ( ( index.column() == 1 || index.column() == 2 ) ) { 00310 00311 QFont savedFont = painter->font(); 00312 QString sumText; 00313 if ( index.column() == 1 && ( ( !expanded && unreadRecursiveCount > 0 ) || ( expanded && unreadCount > 0 ) ) ) { 00314 QFont font = painter->font(); 00315 font.setBold( true ); 00316 painter->setFont( font ); 00317 sumText = QString::number( expanded ? unreadCount : unreadRecursiveCount ); 00318 } else { 00319 00320 qint64 totalCount = statistics.count(); 00321 if (index.column() == 2 && ( ( !expanded && totalRecursiveCount > 0 ) || ( expanded && totalCount > 0 ) ) ) { 00322 sumText = QString::number( expanded ? totalCount : totalRecursiveCount ); 00323 } 00324 } 00325 00326 painter->drawText( textRect, Qt::AlignRight | Qt::AlignVCenter, sumText ); 00327 painter->setFont( savedFont ); 00328 return; 00329 } 00330 00331 //total size 00332 if ( index.column() == 3 && !expanded ) { 00333 if ( textColor.isValid() ) 00334 painter->setPen( textColor ); 00335 painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, KIO::convertSize( (KIO::filesize_t)totalSize ) ); 00336 return; 00337 } 00338 00339 if ( textColor.isValid() ) 00340 painter->setPen( textColor ); 00341 painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, text ); 00342 } 00343 00344 #include "collectionstatisticsdelegate.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue May 8 2012 00:00:41 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue May 8 2012 00:00:41 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.