• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

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 Mon Aug 27 2012 22:09:21 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.8.5 API Reference

Skip menu "kdepimlibs-4.8.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal