• Skip to content
  • Skip to link menu
KDE 4.8 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • Contact Us
 

akonadi

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

akonadi

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • 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
Generated for KDE-PIM Libraries by doxygen 1.7.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal