• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 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 QVariant fetchState = index.data(Akonadi::EntityTreeModel::FetchStateRole);
166  if (!fetchState.isValid() || fetchState.toInt() != Akonadi::EntityTreeModel::FetchingState ) {
167  d->animator->pop(index);
168  return;
169  }
170 
171  d->animator->push( index );
172 
173  if ( QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>( option ) ) {
174  v4->icon = d->animator->sequenceFrame( index );
175  }
176  }
177 }
178 
179 class PainterStateSaver
180 {
181  public:
182  PainterStateSaver( QPainter *painter )
183  {
184  mPainter = painter;
185  mPainter->save();
186  }
187 
188  ~PainterStateSaver()
189  {
190  mPainter->restore();
191  }
192 
193  private:
194  QPainter *mPainter;
195 };
196 
197 void CollectionStatisticsDelegate::paint( QPainter *painter,
198  const QStyleOptionViewItem &option,
199  const QModelIndex &index ) const
200 {
201  Q_D( const CollectionStatisticsDelegate );
202  PainterStateSaver stateSaver( painter );
203 
204  const QColor textColor = index.data( Qt::ForegroundRole ).value<QColor>();
205  // First, paint the basic, but without the text. We remove the text
206  // in initStyleOption(), which gets called by QStyledItemDelegate::paint().
207  QStyledItemDelegate::paint( painter, option, index );
208 
209  // No, we retrieve the correct style option by calling intiStyleOption from
210  // the superclass.
211  QStyleOptionViewItemV4 option4 = option;
212  QStyledItemDelegate::initStyleOption( &option4, index );
213  QString text = option4.text;
214 
215  // Now calculate the rectangle for the text
216  QStyle *s = d->parent->style();
217  const QWidget *widget = option4.widget;
218  const QRect textRect = s->subElementRect( QStyle::SE_ItemViewItemText, &option4, widget );
219 
220  // When checking if the item is expanded, we need to check that for the first
221  // column, as Qt only recognises the index as expanded for the first column
222  const QModelIndex firstColumn = index.sibling( index.row(), 0 );
223  QTreeView* treeView = qobject_cast<QTreeView*>( d->parent );
224  bool expanded = treeView && treeView->isExpanded( firstColumn );
225 
226  if ( option.state & QStyle::State_Selected ) {
227  painter->setPen( textColor.isValid() ? textColor : option.palette.highlightedText().color() );
228  }
229 
230  Collection collection = firstColumn.data( EntityTreeModel::CollectionRole ).value<Collection>();
231 
232  Q_ASSERT( collection.isValid() ); // TODO: I seem to hit this when removing a duplicated "Personal Contacts" or "Personal Calendar"
233 
234  CollectionStatistics statistics = collection.statistics();
235 
236  qint64 unreadCount = qMax( 0LL, statistics.unreadCount() );
237  qint64 totalRecursiveCount = 0;
238  qint64 unreadRecursiveCount = 0;
239  qint64 totalSize = 0;
240  bool needRecursiveCounts = false;
241  bool needTotalSize = false;
242  if ( d->drawUnreadAfterFolder && index.column() == 0 ) {
243  needRecursiveCounts = true;
244  } else if ( ( index.column() == 1 || index.column() == 2 ) ) {
245  needRecursiveCounts = true;
246  } else if ( index.column() == 3 && !expanded ) {
247  needTotalSize = true;
248  }
249 
250  if ( needRecursiveCounts || needTotalSize ) {
251  d->getCountRecursive( firstColumn, totalRecursiveCount, unreadRecursiveCount, totalSize );
252  }
253 
254  // Draw the unread count after the folder name (in parenthesis)
255  if ( d->drawUnreadAfterFolder && index.column() == 0 ) {
256  // Construct the string which will appear after the foldername (with the
257  // unread count)
258  QString unread;
259 // qDebug() << expanded << unreadCount << unreadRecursiveCount;
260  if ( expanded && unreadCount > 0 ) {
261  unread = QString::fromLatin1( " (%1)" ).arg( unreadCount );
262  } else if ( !expanded ) {
263  if ( unreadCount != unreadRecursiveCount ) {
264  unread = QString::fromLatin1( " (%1 + %2)" ).arg( unreadCount ).arg( unreadRecursiveCount - unreadCount );
265  } else if ( unreadCount > 0 ) {
266  unread = QString::fromLatin1( " (%1)" ).arg( unreadCount );
267  }
268  }
269 
270  PainterStateSaver stateSaver( painter );
271 
272  if ( !unread.isEmpty() ) {
273  QFont font = painter->font();
274  font.setBold( true );
275  painter->setFont( font );
276  }
277 
278  const QColor unreadColor = ( option.state & QStyle::State_Selected ) ? d->mSelectedUnreadColor : d->mDeselectedUnreadColor;
279  const QRect iconRect = s->subElementRect( QStyle::SE_ItemViewItemDecoration, &option4, widget );
280 
281  if ( option.decorationPosition == QStyleOptionViewItem::Left ||
282  option.decorationPosition == QStyleOptionViewItem::Right ) {
283  // Squeeze the folder text if it is to big and calculate the rectangles
284  // where the folder text and the unread count will be drawn to
285  QString folderName = text;
286  QFontMetrics fm( painter->fontMetrics() );
287  const int unreadWidth = fm.width( unread );
288  int folderWidth( fm.width( folderName ) );
289  const bool enoughPlaceForText = ( option.rect.width() > ( folderWidth + unreadWidth + iconRect.width() ) );
290 
291  if ( !enoughPlaceForText && ( folderWidth + unreadWidth > textRect.width() ) ) {
292  folderName = fm.elidedText( folderName, Qt::ElideRight,
293  option.rect.width() - unreadWidth - iconRect.width() );
294  folderWidth = fm.width( folderName );
295  }
296  QRect folderRect = textRect;
297  QRect unreadRect = textRect;
298  folderRect.setRight( textRect.left() + folderWidth );
299  unreadRect = QRect( folderRect.right(), folderRect.top(), unreadRect.width(), unreadRect.height() );
300  if ( textColor.isValid() ) {
301  painter->setPen( textColor );
302  }
303 
304  // Draw folder name and unread count
305  painter->drawText( folderRect, Qt::AlignLeft | Qt::AlignVCenter, folderName );
306  painter->setPen( unreadColor );
307  painter->drawText( unreadRect, Qt::AlignLeft | Qt::AlignVCenter, unread );
308  } else if ( option.decorationPosition == QStyleOptionViewItem::Top ) {
309  if ( unreadCount > 0 ) {
310  // draw over the icon
311  painter->setPen( unreadColor );
312  painter->drawText( iconRect, Qt::AlignCenter, QString::number( unreadCount ) );
313  }
314  }
315  return;
316  }
317 
318  // For the unread/total column, paint the summed up count if the item
319  // is collapsed
320  if ( ( index.column() == 1 || index.column() == 2 ) ) {
321 
322  QFont savedFont = painter->font();
323  QString sumText;
324  if ( index.column() == 1 && ( ( !expanded && unreadRecursiveCount > 0 ) || ( expanded && unreadCount > 0 ) ) ) {
325  QFont font = painter->font();
326  font.setBold( true );
327  painter->setFont( font );
328  sumText = QString::number( expanded ? unreadCount : unreadRecursiveCount );
329  } else {
330 
331  qint64 totalCount = statistics.count();
332  if ( index.column() == 2 && ( ( !expanded && totalRecursiveCount > 0 ) || ( expanded && totalCount > 0 ) ) ) {
333  sumText = QString::number( expanded ? totalCount : totalRecursiveCount );
334  }
335  }
336 
337  painter->drawText( textRect, Qt::AlignRight | Qt::AlignVCenter, sumText );
338  painter->setFont( savedFont );
339  return;
340  }
341 
342  //total size
343  if ( index.column() == 3 && !expanded ) {
344  if ( textColor.isValid() ) {
345  painter->setPen( textColor );
346  }
347  painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, KIO::convertSize( ( KIO::filesize_t)totalSize ) );
348  return;
349  }
350 
351  if ( textColor.isValid() ) {
352  painter->setPen( textColor );
353  }
354  painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, text );
355 }
356 
357 void CollectionStatisticsDelegate::updatePalette()
358 {
359  Q_D( CollectionStatisticsDelegate );
360  d->updateColor();
361 }
362 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:27:33 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.5 API Reference

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