• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.1 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 <QtGui/QPainter>
29 #include <QtGui/QStyle>
30 #include <QtGui/QStyleOption>
31 #include <QtGui/QStyleOptionViewItemV4>
32 #include <QtGui/QAbstractItemView>
33 #include <QtGui/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  if ( enable ) {
135  Q_ASSERT( !d->animator );
136  Akonadi::DelegateAnimator *animator = new Akonadi::DelegateAnimator( d->parent );
137  d->animator = animator;
138  } else {
139  delete d->animator;
140  d->animator = 0;
141  }
142 }
143 
144 bool CollectionStatisticsDelegate::progressAnimationEnabled() const
145 {
146  Q_D( const CollectionStatisticsDelegate );
147  return d->animator != 0;
148 }
149 
150 void CollectionStatisticsDelegate::initStyleOption( QStyleOptionViewItem *option,
151  const QModelIndex &index ) const
152 {
153  Q_D( const CollectionStatisticsDelegate );
154 
155  QStyleOptionViewItemV4 *noTextOption =
156  qstyleoption_cast<QStyleOptionViewItemV4 *>( option );
157  QStyledItemDelegate::initStyleOption( noTextOption, index );
158  if ( option->decorationPosition != QStyleOptionViewItem::Top ) {
159  noTextOption->text.clear();
160  }
161 
162  if ( d->animator ) {
163 
164  const Akonadi::Collection collection = index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
165 
166  if (!collection.isValid())
167  {
168  d->animator->pop(index);
169  return;
170  }
171 
172  if (index.data(Akonadi::EntityTreeModel::FetchStateRole).toInt() != Akonadi::EntityTreeModel::FetchingState)
173  {
174  d->animator->pop(index);
175  return;
176  }
177 
178  d->animator->push(index);
179 
180  if (QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>(option)) {
181  v4->icon = d->animator->sequenceFrame(index);
182  }
183  }
184 }
185 
186 class PainterStateSaver
187 {
188  public:
189  PainterStateSaver( QPainter *painter )
190  {
191  mPainter = painter;
192  mPainter->save();
193  }
194 
195  ~PainterStateSaver()
196  {
197  mPainter->restore();
198  }
199 
200  private:
201  QPainter *mPainter;
202 };
203 
204 void CollectionStatisticsDelegate::paint( QPainter *painter,
205  const QStyleOptionViewItem &option,
206  const QModelIndex &index ) const
207 {
208  Q_D( const CollectionStatisticsDelegate );
209  PainterStateSaver stateSaver( painter );
210 
211  const QColor textColor = index.data( Qt::ForegroundRole ).value<QColor>();
212  // First, paint the basic, but without the text. We remove the text
213  // in initStyleOption(), which gets called by QStyledItemDelegate::paint().
214  QStyledItemDelegate::paint( painter, option, index );
215 
216  // No, we retrieve the correct style option by calling intiStyleOption from
217  // the superclass.
218  QStyleOptionViewItemV4 option4 = option;
219  QStyledItemDelegate::initStyleOption( &option4, index );
220  QString text = option4.text;
221 
222  // Now calculate the rectangle for the text
223  QStyle *s = d->parent->style();
224  const QWidget *widget = option4.widget;
225  const QRect textRect = s->subElementRect( QStyle::SE_ItemViewItemText, &option4, widget );
226 
227  // When checking if the item is expanded, we need to check that for the first
228  // column, as Qt only recogises the index as expanded for the first column
229  QModelIndex firstColumn = index.model()->index( index.row(), 0, index.parent() );
230  QTreeView* treeView = qobject_cast<QTreeView*>( d->parent );
231  bool expanded = treeView && treeView->isExpanded( firstColumn );
232 
233  if ( option.state & QStyle::State_Selected ) {
234  painter->setPen( textColor.isValid() ? textColor : option.palette.highlightedText().color() );
235  }
236 
237  Collection collection = index.sibling( index.row(), 0 ).data( EntityTreeModel::CollectionRole ).value<Collection>();
238 
239  Q_ASSERT(collection.isValid());
240 
241  CollectionStatistics statistics = collection.statistics();
242 
243  qint64 unreadCount = qMax( 0LL, statistics.unreadCount() );
244  qint64 totalRecursiveCount = 0;
245  qint64 unreadRecursiveCount = 0;
246  qint64 totalSize = 0;
247  d->getCountRecursive( index.sibling( index.row(), 0 ), totalRecursiveCount, unreadRecursiveCount, totalSize );
248 
249  // Draw the unread count after the folder name (in parenthesis)
250  if ( d->drawUnreadAfterFolder && index.column() == 0 ) {
251  // Construct the string which will appear after the foldername (with the
252  // unread count)
253  QString unread;
254 // qDebug() << expanded << unreadCount << unreadRecursiveCount;
255  if ( expanded && unreadCount > 0 )
256  unread = QString::fromLatin1( " (%1)" ).arg( unreadCount );
257  else if ( !expanded ) {
258  if ( unreadCount != unreadRecursiveCount )
259  unread = QString::fromLatin1( " (%1 + %2)" ).arg( unreadCount ).arg( unreadRecursiveCount - unreadCount );
260  else if ( unreadCount > 0 )
261  unread = QString::fromLatin1( " (%1)" ).arg( unreadCount );
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  // Draw folder name and unread count
298  painter->drawText( folderRect, Qt::AlignLeft | Qt::AlignVCenter, folderName );
299  painter->setPen( unreadColor );
300  painter->drawText( unreadRect, Qt::AlignLeft | Qt::AlignVCenter, unread );
301  } else if ( option.decorationPosition == QStyleOptionViewItem::Top ) {
302  if ( unreadCount > 0 ) {
303  // draw over the icon
304  painter->setPen( unreadColor );
305  painter->drawText( iconRect, Qt::AlignCenter, QString::number( unreadCount ) );
306  }
307  }
308  return;
309  }
310 
311  // For the unread/total column, paint the summed up count if the item
312  // is collapsed
313  if ( ( index.column() == 1 || index.column() == 2 ) ) {
314 
315  QFont savedFont = painter->font();
316  QString sumText;
317  if ( index.column() == 1 && ( ( !expanded && unreadRecursiveCount > 0 ) || ( expanded && unreadCount > 0 ) ) ) {
318  QFont font = painter->font();
319  font.setBold( true );
320  painter->setFont( font );
321  sumText = QString::number( expanded ? unreadCount : unreadRecursiveCount );
322  } else {
323 
324  qint64 totalCount = statistics.count();
325  if (index.column() == 2 && ( ( !expanded && totalRecursiveCount > 0 ) || ( expanded && totalCount > 0 ) ) ) {
326  sumText = QString::number( expanded ? totalCount : totalRecursiveCount );
327  }
328  }
329 
330  painter->drawText( textRect, Qt::AlignRight | Qt::AlignVCenter, sumText );
331  painter->setFont( savedFont );
332  return;
333  }
334 
335  //total size
336  if ( index.column() == 3 && !expanded ) {
337  if ( textColor.isValid() )
338  painter->setPen( textColor );
339  painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, KIO::convertSize( (KIO::filesize_t)totalSize ) );
340  return;
341  }
342 
343  if ( textColor.isValid() )
344  painter->setPen( textColor );
345  painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, text );
346 }
347 
348 void CollectionStatisticsDelegate::updatePalette()
349 {
350  Q_D( CollectionStatisticsDelegate );
351  d->updateColor();
352 }
353 
354 #include "collectionstatisticsdelegate.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Sep 24 2012 09:06:25 by doxygen 1.8.1.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.9.1 API Reference

Skip menu "kdepimlibs-4.9.1 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