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

akonadi

  • akonadi
collectionstatisticsdelegate.cpp
1 /*
2  Copyright (c) 2008 Thomas McGuire <thomas.mcguire@gmx.net>
3  Copyright (c) 2012 Laurent Montel <montel@kde.org>
4 
5  This library is free software; you can redistribute it and/or modify it
6  under the terms of the GNU Library General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or (at your
8  option) any later version.
9 
10  This library is distributed in the hope that it will be useful, but WITHOUT
11  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13  License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to the
17  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  02110-1301, USA.
19 */
20 
21 #include "collectionstatisticsdelegate.h"
22 #include "collectionstatisticsmodel.h"
23 
24 #include <kcolorscheme.h>
25 #include <kdebug.h>
26 #include <kio/global.h>
27 
28 #include <QPainter>
29 #include <QStyle>
30 #include <QStyleOption>
31 #include <QStyleOptionViewItemV4>
32 #include <QAbstractItemView>
33 #include <QTreeView>
34 
35 #include "entitytreemodel.h"
36 #include "collectionstatistics.h"
37 #include "collection.h"
38 #include "progressspinnerdelegate_p.h"
39 
40 using namespace Akonadi;
41 
42 namespace Akonadi {
43 
44 enum CountType
45 {
46  UnreadCount,
47  TotalCount
48 };
49 
50 class CollectionStatisticsDelegatePrivate
51 {
52  public:
53  QAbstractItemView *parent;
54  bool drawUnreadAfterFolder;
55  DelegateAnimator *animator;
56  QColor mSelectedUnreadColor;
57  QColor mDeselectedUnreadColor;
58 
59  CollectionStatisticsDelegatePrivate( QAbstractItemView *treeView )
60  : parent( treeView ),
61  drawUnreadAfterFolder( false ),
62  animator( 0 )
63  {
64  updateColor();
65  }
66 
67  void getCountRecursive( const QModelIndex &index, qint64 &totalCount, qint64 &unreadCount, qint64 &totalSize ) const
68  {
69  Collection collection = qvariant_cast<Collection>( index.data( EntityTreeModel::CollectionRole ) );
70  // Do not assert on invalid collections, since a collection may be deleted
71  // in the meantime and deleted collections are invalid.
72  if ( collection.isValid() ) {
73  CollectionStatistics statistics = collection.statistics();
74  totalCount += qMax( 0LL, statistics.count() );
75  unreadCount += qMax( 0LL, statistics.unreadCount() );
76  totalSize += qMax( 0LL, statistics.size() );
77  if ( index.model()->hasChildren( index ) ) {
78  const int rowCount = index.model()->rowCount( index );
79  for ( int row = 0; row < rowCount; row++ ) {
80  static const int column = 0;
81  getCountRecursive( index.model()->index( row, column, index ), totalCount, unreadCount, totalSize );
82  }
83  }
84  }
85  }
86 
87  void updateColor()
88  {
89  mSelectedUnreadColor = KColorScheme( QPalette::Active, KColorScheme::Selection )
90  .foreground( KColorScheme::LinkText ).color();
91  mDeselectedUnreadColor = KColorScheme( QPalette::Active, KColorScheme::View )
92  .foreground( KColorScheme::LinkText ).color();
93  }
94 };
95 
96 }
97 
98 CollectionStatisticsDelegate::CollectionStatisticsDelegate( QAbstractItemView *parent )
99  : QStyledItemDelegate( parent ),
100  d_ptr( new CollectionStatisticsDelegatePrivate( parent ) )
101 {
102 
103 }
104 
105 CollectionStatisticsDelegate::CollectionStatisticsDelegate( QTreeView *parent )
106  : QStyledItemDelegate( parent ),
107  d_ptr( new CollectionStatisticsDelegatePrivate( parent ) )
108 {
109 
110 }
111 
112 CollectionStatisticsDelegate::~CollectionStatisticsDelegate()
113 {
114  delete d_ptr;
115 }
116 
117 void CollectionStatisticsDelegate::setUnreadCountShown( bool enable )
118 {
119  Q_D( CollectionStatisticsDelegate );
120  d->drawUnreadAfterFolder = enable;
121 }
122 
123 bool CollectionStatisticsDelegate::unreadCountShown() const
124 {
125  Q_D( const CollectionStatisticsDelegate );
126  return d->drawUnreadAfterFolder;
127 }
128 
129 void CollectionStatisticsDelegate::setProgressAnimationEnabled( bool enable )
130 {
131  Q_D( CollectionStatisticsDelegate );
132  if ( enable == ( d->animator != 0 ) ) {
133  return;
134  }
135  if ( enable ) {
136  Q_ASSERT( !d->animator );
137  Akonadi::DelegateAnimator *animator = new Akonadi::DelegateAnimator( d->parent );
138  d->animator = animator;
139  } else {
140  delete d->animator;
141  d->animator = 0;
142  }
143 }
144 
145 bool CollectionStatisticsDelegate::progressAnimationEnabled() const
146 {
147  Q_D( const CollectionStatisticsDelegate );
148  return d->animator != 0;
149 }
150 
151 void CollectionStatisticsDelegate::initStyleOption( QStyleOptionViewItem *option,
152  const QModelIndex &index ) const
153 {
154  Q_D( const CollectionStatisticsDelegate );
155 
156  QStyleOptionViewItemV4 *noTextOption =
157  qstyleoption_cast<QStyleOptionViewItemV4 *>( option );
158  QStyledItemDelegate::initStyleOption( noTextOption, index );
159  if ( option->decorationPosition != QStyleOptionViewItem::Top ) {
160  noTextOption->text.clear();
161  }
162 
163  if ( d->animator ) {
164 
165  const Akonadi::Collection collection = index.data( Akonadi::EntityTreeModel::CollectionRole ).value<Akonadi::Collection>();
166 
167  if ( !collection.isValid() ) {
168  d->animator->pop( index );
169  return;
170  }
171 
172  if ( index.data( Akonadi::EntityTreeModel::FetchStateRole ).toInt() != Akonadi::EntityTreeModel::FetchingState ) {
173  d->animator->pop( index );
174  return;
175  }
176 
177  d->animator->push( index );
178 
179  if ( QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>( option ) ) {
180  v4->icon = d->animator->sequenceFrame( index );
181  }
182  }
183 }
184 
185 class PainterStateSaver
186 {
187  public:
188  PainterStateSaver( QPainter *painter )
189  {
190  mPainter = painter;
191  mPainter->save();
192  }
193 
194  ~PainterStateSaver()
195  {
196  mPainter->restore();
197  }
198 
199  private:
200  QPainter *mPainter;
201 };
202 
203 void CollectionStatisticsDelegate::paint( QPainter *painter,
204  const QStyleOptionViewItem &option,
205  const QModelIndex &index ) const
206 {
207  Q_D( const CollectionStatisticsDelegate );
208  PainterStateSaver stateSaver( painter );
209 
210  const QColor textColor = index.data( Qt::ForegroundRole ).value<QColor>();
211  // First, paint the basic, but without the text. We remove the text
212  // in initStyleOption(), which gets called by QStyledItemDelegate::paint().
213  QStyledItemDelegate::paint( painter, option, index );
214 
215  // No, we retrieve the correct style option by calling intiStyleOption from
216  // the superclass.
217  QStyleOptionViewItemV4 option4 = option;
218  QStyledItemDelegate::initStyleOption( &option4, index );
219  QString text = option4.text;
220 
221  // Now calculate the rectangle for the text
222  QStyle *s = d->parent->style();
223  const QWidget *widget = option4.widget;
224  const QRect textRect = s->subElementRect( QStyle::SE_ItemViewItemText, &option4, widget );
225 
226  // When checking if the item is expanded, we need to check that for the first
227  // column, as Qt only recogises the index as expanded for the first column
228  QModelIndex firstColumn = index.model()->index( index.row(), 0, index.parent() );
229  QTreeView* treeView = qobject_cast<QTreeView*>( d->parent );
230  bool expanded = treeView && treeView->isExpanded( firstColumn );
231 
232  if ( option.state & QStyle::State_Selected ) {
233  painter->setPen( textColor.isValid() ? textColor : option.palette.highlightedText().color() );
234  }
235 
236  Collection collection = index.sibling( index.row(), 0 ).data( EntityTreeModel::CollectionRole ).value<Collection>();
237 
238  Q_ASSERT( collection.isValid() );
239 
240  CollectionStatistics statistics = collection.statistics();
241 
242  qint64 unreadCount = qMax( 0LL, statistics.unreadCount() );
243  qint64 totalRecursiveCount = 0;
244  qint64 unreadRecursiveCount = 0;
245  qint64 totalSize = 0;
246  d->getCountRecursive( index.sibling( index.row(), 0 ), totalRecursiveCount, unreadRecursiveCount, totalSize );
247 
248  // Draw the unread count after the folder name (in parenthesis)
249  if ( d->drawUnreadAfterFolder && index.column() == 0 ) {
250  // Construct the string which will appear after the foldername (with the
251  // unread count)
252  QString unread;
253 // qDebug() << expanded << unreadCount << unreadRecursiveCount;
254  if ( expanded && unreadCount > 0 ) {
255  unread = QString::fromLatin1( " (%1)" ).arg( unreadCount );
256  } else if ( !expanded ) {
257  if ( unreadCount != unreadRecursiveCount ) {
258  unread = QString::fromLatin1( " (%1 + %2)" ).arg( unreadCount ).arg( unreadRecursiveCount - unreadCount );
259  } else if ( unreadCount > 0 ) {
260  unread = QString::fromLatin1( " (%1)" ).arg( unreadCount );
261  }
262  }
263 
264  PainterStateSaver stateSaver( painter );
265 
266  if ( !unread.isEmpty() ) {
267  QFont font = painter->font();
268  font.setBold( true );
269  painter->setFont( font );
270  }
271 
272  const QColor unreadColor = ( option.state & QStyle::State_Selected ) ? d->mSelectedUnreadColor : d->mDeselectedUnreadColor;
273  const QRect iconRect = s->subElementRect( QStyle::SE_ItemViewItemDecoration, &option4, widget );
274 
275  if ( option.decorationPosition == QStyleOptionViewItem::Left ||
276  option.decorationPosition == QStyleOptionViewItem::Right ) {
277  // Squeeze the folder text if it is to big and calculate the rectangles
278  // where the folder text and the unread count will be drawn to
279  QString folderName = text;
280  QFontMetrics fm( painter->fontMetrics() );
281  const int unreadWidth = fm.width( unread );
282  int folderWidth( fm.width( folderName ) );
283  const bool enoughPlaceForText = ( option.rect.width() > ( folderWidth + unreadWidth + iconRect.width() ) );
284 
285  if ( !enoughPlaceForText && ( folderWidth + unreadWidth > textRect.width() ) ) {
286  folderName = fm.elidedText( folderName, Qt::ElideRight,
287  option.rect.width() - unreadWidth - iconRect.width() );
288  folderWidth = fm.width( folderName );
289  }
290  QRect folderRect = textRect;
291  QRect unreadRect = textRect;
292  folderRect.setRight( textRect.left() + folderWidth );
293  unreadRect = QRect( folderRect.right(), folderRect.top(), unreadRect.width(), unreadRect.height() );
294  if ( textColor.isValid() ) {
295  painter->setPen( textColor );
296  }
297 
298  // Draw folder name and unread count
299  painter->drawText( folderRect, Qt::AlignLeft | Qt::AlignVCenter, folderName );
300  painter->setPen( unreadColor );
301  painter->drawText( unreadRect, Qt::AlignLeft | Qt::AlignVCenter, unread );
302  } else if ( option.decorationPosition == QStyleOptionViewItem::Top ) {
303  if ( unreadCount > 0 ) {
304  // draw over the icon
305  painter->setPen( unreadColor );
306  painter->drawText( iconRect, Qt::AlignCenter, QString::number( unreadCount ) );
307  }
308  }
309  return;
310  }
311 
312  // For the unread/total column, paint the summed up count if the item
313  // is collapsed
314  if ( ( index.column() == 1 || index.column() == 2 ) ) {
315 
316  QFont savedFont = painter->font();
317  QString sumText;
318  if ( index.column() == 1 && ( ( !expanded && unreadRecursiveCount > 0 ) || ( expanded && unreadCount > 0 ) ) ) {
319  QFont font = painter->font();
320  font.setBold( true );
321  painter->setFont( font );
322  sumText = QString::number( expanded ? unreadCount : unreadRecursiveCount );
323  } else {
324 
325  qint64 totalCount = statistics.count();
326  if ( index.column() == 2 && ( ( !expanded && totalRecursiveCount > 0 ) || ( expanded && totalCount > 0 ) ) ) {
327  sumText = QString::number( expanded ? totalCount : totalRecursiveCount );
328  }
329  }
330 
331  painter->drawText( textRect, Qt::AlignRight | Qt::AlignVCenter, sumText );
332  painter->setFont( savedFont );
333  return;
334  }
335 
336  //total size
337  if ( index.column() == 3 && !expanded ) {
338  if ( textColor.isValid() ) {
339  painter->setPen( textColor );
340  }
341  painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, KIO::convertSize( ( KIO::filesize_t)totalSize ) );
342  return;
343  }
344 
345  if ( textColor.isValid() ) {
346  painter->setPen( textColor );
347  }
348  painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, text );
349 }
350 
351 void CollectionStatisticsDelegate::updatePalette()
352 {
353  Q_D( CollectionStatisticsDelegate );
354  d->updateColor();
355 }
356 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Fri Mar 8 2013 21:49:50 by doxygen 1.8.3.1 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.10.0 API Reference

Skip menu "kdepimlibs-4.10.0 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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