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

akonadi

  • sources
  • kde-4.12
  • kdepimlibs
  • 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  if ( !collection.isValid() )
233  kError() << "Invalid collection: " << collection;
234 
235  Q_ASSERT( collection.isValid() ); // TODO: I seem to hit this when removing a duplicated "Personal Contacts" or "Personal Calendar"
236 
237  CollectionStatistics statistics = collection.statistics();
238 
239  qint64 unreadCount = qMax( 0LL, statistics.unreadCount() );
240  qint64 totalRecursiveCount = 0;
241  qint64 unreadRecursiveCount = 0;
242  qint64 totalSize = 0;
243  bool needRecursiveCounts = false;
244  bool needTotalSize = false;
245  if ( d->drawUnreadAfterFolder && index.column() == 0 ) {
246  needRecursiveCounts = true;
247  } else if ( ( index.column() == 1 || index.column() == 2 ) ) {
248  needRecursiveCounts = true;
249  } else if ( index.column() == 3 && !expanded ) {
250  needTotalSize = true;
251  }
252 
253  if ( needRecursiveCounts || needTotalSize ) {
254  d->getCountRecursive( firstColumn, totalRecursiveCount, unreadRecursiveCount, totalSize );
255  }
256 
257  // Draw the unread count after the folder name (in parenthesis)
258  if ( d->drawUnreadAfterFolder && index.column() == 0 ) {
259  // Construct the string which will appear after the foldername (with the
260  // unread count)
261  QString unread;
262 // qDebug() << expanded << unreadCount << unreadRecursiveCount;
263  if ( expanded && unreadCount > 0 ) {
264  unread = QString::fromLatin1( " (%1)" ).arg( unreadCount );
265  } else if ( !expanded ) {
266  if ( unreadCount != unreadRecursiveCount ) {
267  unread = QString::fromLatin1( " (%1 + %2)" ).arg( unreadCount ).arg( unreadRecursiveCount - unreadCount );
268  } else if ( unreadCount > 0 ) {
269  unread = QString::fromLatin1( " (%1)" ).arg( unreadCount );
270  }
271  }
272 
273  PainterStateSaver stateSaver( painter );
274 
275  if ( !unread.isEmpty() ) {
276  QFont font = painter->font();
277  font.setBold( true );
278  painter->setFont( font );
279  }
280 
281  const QColor unreadColor = ( option.state & QStyle::State_Selected ) ? d->mSelectedUnreadColor : d->mDeselectedUnreadColor;
282  const QRect iconRect = s->subElementRect( QStyle::SE_ItemViewItemDecoration, &option4, widget );
283 
284  if ( option.decorationPosition == QStyleOptionViewItem::Left ||
285  option.decorationPosition == QStyleOptionViewItem::Right ) {
286  // Squeeze the folder text if it is to big and calculate the rectangles
287  // where the folder text and the unread count will be drawn to
288  QString folderName = text;
289  QFontMetrics fm( painter->fontMetrics() );
290  const int unreadWidth = fm.width( unread );
291  int folderWidth( fm.width( folderName ) );
292  const bool enoughPlaceForText = ( option.rect.width() > ( folderWidth + unreadWidth + iconRect.width() ) );
293 
294  if ( !enoughPlaceForText && ( folderWidth + unreadWidth > textRect.width() ) ) {
295  folderName = fm.elidedText( folderName, Qt::ElideRight,
296  option.rect.width() - unreadWidth - iconRect.width() );
297  folderWidth = fm.width( folderName );
298  }
299  QRect folderRect = textRect;
300  QRect unreadRect = textRect;
301  folderRect.setRight( textRect.left() + folderWidth );
302  unreadRect = QRect( folderRect.right(), folderRect.top(), unreadRect.width(), unreadRect.height() );
303  if ( textColor.isValid() ) {
304  painter->setPen( textColor );
305  }
306 
307  // Draw folder name and unread count
308  painter->drawText( folderRect, Qt::AlignLeft | Qt::AlignVCenter, folderName );
309  painter->setPen( unreadColor );
310  painter->drawText( unreadRect, Qt::AlignLeft | Qt::AlignVCenter, unread );
311  } else if ( option.decorationPosition == QStyleOptionViewItem::Top ) {
312  if ( unreadCount > 0 ) {
313  // draw over the icon
314  painter->setPen( unreadColor );
315  painter->drawText( iconRect, Qt::AlignCenter, QString::number( unreadCount ) );
316  }
317  }
318  return;
319  }
320 
321  // For the unread/total column, paint the summed up count if the item
322  // is collapsed
323  if ( ( index.column() == 1 || index.column() == 2 ) ) {
324 
325  QFont savedFont = painter->font();
326  QString sumText;
327  if ( index.column() == 1 && ( ( !expanded && unreadRecursiveCount > 0 ) || ( expanded && unreadCount > 0 ) ) ) {
328  QFont font = painter->font();
329  font.setBold( true );
330  painter->setFont( font );
331  sumText = QString::number( expanded ? unreadCount : unreadRecursiveCount );
332  } else {
333 
334  qint64 totalCount = statistics.count();
335  if ( index.column() == 2 && ( ( !expanded && totalRecursiveCount > 0 ) || ( expanded && totalCount > 0 ) ) ) {
336  sumText = QString::number( expanded ? totalCount : totalRecursiveCount );
337  }
338  }
339 
340  painter->drawText( textRect, Qt::AlignRight | Qt::AlignVCenter, sumText );
341  painter->setFont( savedFont );
342  return;
343  }
344 
345  //total size
346  if ( index.column() == 3 && !expanded ) {
347  if ( textColor.isValid() ) {
348  painter->setPen( textColor );
349  }
350  painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, KIO::convertSize( ( KIO::filesize_t)totalSize ) );
351  return;
352  }
353 
354  if ( textColor.isValid() ) {
355  painter->setPen( textColor );
356  }
357  painter->drawText( textRect, option4.displayAlignment | Qt::AlignVCenter, text );
358 }
359 
360 void CollectionStatisticsDelegate::updatePalette()
361 {
362  Q_D( CollectionStatisticsDelegate );
363  d->updateColor();
364 }
365 
Akonadi::CollectionStatisticsDelegate::~CollectionStatisticsDelegate
~CollectionStatisticsDelegate()
Destroys the collection statistics delegate.
Definition: collectionstatisticsdelegate.cpp:112
Akonadi::CollectionStatistics::count
qint64 count() const
Returns the number of items in this collection or -1 if this information is not available.
Definition: collectionstatistics.cpp:67
Akonadi::CollectionStatisticsDelegate::setProgressAnimationEnabled
void setProgressAnimationEnabled(bool enable)
Definition: collectionstatisticsdelegate.cpp:129
Akonadi::CollectionStatistics
Provides statistics information of a Collection.
Definition: collectionstatistics.h:69
Akonadi::EntityTreeModel::FetchStateRole
Returns the FetchState of a particular item.
Definition: entitytreemodel.h:350
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
Akonadi::CollectionStatisticsDelegate::updatePalette
void updatePalette()
Definition: collectionstatisticsdelegate.cpp:360
Akonadi::CollectionStatisticsDelegate::initStyleOption
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
Definition: collectionstatisticsdelegate.cpp:151
Akonadi::EntityTreeModel::CollectionRole
The collection.
Definition: entitytreemodel.h:335
Akonadi::CollectionStatisticsDelegate::unreadCountShown
bool unreadCountShown() const
Returns whether the unread count is drawn next to the folder name.
Definition: collectionstatisticsdelegate.cpp:123
Akonadi::CollectionStatisticsDelegate::CollectionStatisticsDelegate
CollectionStatisticsDelegate(QAbstractItemView *parent)
Creates a new collection statistics delegate.
Definition: collectionstatisticsdelegate.cpp:98
Akonadi::CollectionStatisticsDelegate::paint
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
Definition: collectionstatisticsdelegate.cpp:197
Akonadi::CollectionStatisticsDelegate::setUnreadCountShown
void setUnreadCountShown(bool enable)
Sets whether the unread count is drawn next to the folder name.
Definition: collectionstatisticsdelegate.cpp:117
Akonadi::EntityTreeModel::FetchingState
There is a fetch of items in this collection in progress.
Definition: entitytreemodel.h:374
Akonadi::CollectionStatistics::unreadCount
qint64 unreadCount() const
Returns the number of unread items in this collection or -1 if this information is not available...
Definition: collectionstatistics.cpp:77
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
Akonadi::CollectionStatisticsDelegate
A delegate that draws unread and total count for CollectionStatisticsModel.
Definition: collectionstatisticsdelegate.h:64
Akonadi::Collection::statistics
CollectionStatistics statistics() const
Returns the collection statistics of the collection.
Definition: collection.cpp:238
Akonadi::CollectionStatistics::size
qint64 size() const
Returns the total size of the items in this collection or -1 if this information is not available...
Definition: collectionstatistics.cpp:87
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:00:26 by doxygen 1.8.7 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 API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

Search



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