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

akonadi

  • sources
  • kde-4.14
  • 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  UnreadCount,
46  TotalCount
47 };
48 
49 class CollectionStatisticsDelegatePrivate
50 {
51 public:
52  QAbstractItemView *parent;
53  bool drawUnreadAfterFolder;
54  DelegateAnimator *animator;
55  QColor mSelectedUnreadColor;
56  QColor mDeselectedUnreadColor;
57 
58  CollectionStatisticsDelegatePrivate(QAbstractItemView *treeView)
59  : parent(treeView)
60  , drawUnreadAfterFolder(false)
61  , animator(0)
62  {
63  updateColor();
64  }
65 
66  void getCountRecursive(const QModelIndex &index, qint64 &totalCount, qint64 &unreadCount, qint64 &totalSize) const
67  {
68  Collection collection = qvariant_cast<Collection>(index.data(EntityTreeModel::CollectionRole));
69  // Do not assert on invalid collections, since a collection may be deleted
70  // in the meantime and deleted collections are invalid.
71  if (collection.isValid()) {
72  CollectionStatistics statistics = collection.statistics();
73  totalCount += qMax(0LL, statistics.count());
74  unreadCount += qMax(0LL, statistics.unreadCount());
75  totalSize += qMax(0LL, statistics.size());
76  if (index.model()->hasChildren(index)) {
77  const int rowCount = index.model()->rowCount(index);
78  for (int row = 0; row < rowCount; row++) {
79  static const int column = 0;
80  getCountRecursive(index.model()->index(row, column, index), totalCount, unreadCount, totalSize);
81  }
82  }
83  }
84  }
85 
86  void updateColor()
87  {
88  mSelectedUnreadColor = KColorScheme(QPalette::Active, KColorScheme::Selection)
89  .foreground(KColorScheme::LinkText).color();
90  mDeselectedUnreadColor = KColorScheme(QPalette::Active, KColorScheme::View)
91  .foreground(KColorScheme::LinkText).color();
92  }
93 };
94 
95 }
96 
97 CollectionStatisticsDelegate::CollectionStatisticsDelegate(QAbstractItemView *parent)
98  : QStyledItemDelegate(parent)
99  , d_ptr(new CollectionStatisticsDelegatePrivate(parent))
100 {
101 
102 }
103 
104 CollectionStatisticsDelegate::CollectionStatisticsDelegate(QTreeView *parent)
105  : QStyledItemDelegate(parent)
106  , d_ptr(new CollectionStatisticsDelegatePrivate(parent))
107 {
108 
109 }
110 
111 CollectionStatisticsDelegate::~CollectionStatisticsDelegate()
112 {
113  delete d_ptr;
114 }
115 
116 void CollectionStatisticsDelegate::setUnreadCountShown(bool enable)
117 {
118  Q_D(CollectionStatisticsDelegate);
119  d->drawUnreadAfterFolder = enable;
120 }
121 
122 bool CollectionStatisticsDelegate::unreadCountShown() const
123 {
124  Q_D(const CollectionStatisticsDelegate);
125  return d->drawUnreadAfterFolder;
126 }
127 
128 void CollectionStatisticsDelegate::setProgressAnimationEnabled(bool enable)
129 {
130  Q_D(CollectionStatisticsDelegate);
131  if (enable == (d->animator != 0)) {
132  return;
133  }
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 QVariant fetchState = index.data(Akonadi::EntityTreeModel::FetchStateRole);
165  if (!fetchState.isValid() || fetchState.toInt() != Akonadi::EntityTreeModel::FetchingState) {
166  d->animator->pop(index);
167  return;
168  }
169 
170  d->animator->push(index);
171 
172  if (QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>(option)) {
173  v4->icon = d->animator->sequenceFrame(index);
174  }
175  }
176 }
177 
178 class PainterStateSaver
179 {
180 public:
181  PainterStateSaver(QPainter *painter)
182  {
183  mPainter = painter;
184  mPainter->save();
185  }
186 
187  ~PainterStateSaver()
188  {
189  mPainter->restore();
190  }
191 
192 private:
193  QPainter *mPainter;
194 };
195 
196 void CollectionStatisticsDelegate::paint(QPainter *painter,
197  const QStyleOptionViewItem &option,
198  const QModelIndex &index) const
199 {
200  Q_D(const CollectionStatisticsDelegate);
201  PainterStateSaver stateSaver(painter);
202 
203  const QColor textColor = index.data(Qt::ForegroundRole).value<QColor>();
204  // First, paint the basic, but without the text. We remove the text
205  // in initStyleOption(), which gets called by QStyledItemDelegate::paint().
206  QStyledItemDelegate::paint(painter, option, index);
207 
208  // Now, we retrieve the correct style option by calling initStyleOption from
209  // the superclass.
210  QStyleOptionViewItemV4 option4 = option;
211  QStyledItemDelegate::initStyleOption(&option4, index);
212  QString text = option4.text;
213 
214  // Now calculate the rectangle for the text
215  QStyle *s = d->parent->style();
216  const QWidget *widget = option4.widget;
217  const QRect textRect = s->subElementRect(QStyle::SE_ItemViewItemText, &option4, widget);
218 
219  // When checking if the item is expanded, we need to check that for the first
220  // column, as Qt only recognises the index as expanded for the first column
221  const QModelIndex firstColumn = index.sibling(index.row(), 0);
222  QTreeView *treeView = qobject_cast<QTreeView *>(d->parent);
223  bool expanded = treeView && treeView->isExpanded(firstColumn);
224 
225  if (option.state & QStyle::State_Selected) {
226  painter->setPen(textColor.isValid() ? textColor : option.palette.highlightedText().color());
227  }
228 
229  Collection collection = firstColumn.data(EntityTreeModel::CollectionRole).value<Collection>();
230 
231  if (!collection.isValid()) {
232  kError() << "Invalid collection: " << collection;
233  return;
234  }
235 
236  CollectionStatistics statistics = collection.statistics();
237 
238  qint64 unreadCount = qMax(0LL, statistics.unreadCount());
239  qint64 totalRecursiveCount = 0;
240  qint64 unreadRecursiveCount = 0;
241  qint64 totalSize = 0;
242  bool needRecursiveCounts = false;
243  bool needTotalSize = false;
244  if (d->drawUnreadAfterFolder && index.column() == 0) {
245  needRecursiveCounts = true;
246  } else if ((index.column() == 1 || index.column() == 2)) {
247  needRecursiveCounts = true;
248  } else if (index.column() == 3 && !expanded) {
249  needTotalSize = true;
250  }
251 
252  if (needRecursiveCounts || needTotalSize) {
253  d->getCountRecursive(firstColumn, totalRecursiveCount, unreadRecursiveCount, totalSize);
254  }
255 
256  // Draw the unread count after the folder name (in parenthesis)
257  if (d->drawUnreadAfterFolder && index.column() == 0) {
258  // Construct the string which will appear after the foldername (with the
259  // unread count)
260  QString unread;
261 // qDebug() << expanded << unreadCount << unreadRecursiveCount;
262  if (expanded && unreadCount > 0) {
263  unread = QString::fromLatin1(" (%1)").arg(unreadCount);
264  } else if (!expanded) {
265  if (unreadCount != unreadRecursiveCount) {
266  unread = QString::fromLatin1(" (%1 + %2)").arg(unreadCount).arg(unreadRecursiveCount - unreadCount);
267  } else if (unreadCount > 0) {
268  unread = QString::fromLatin1(" (%1)").arg(unreadCount);
269  }
270  }
271 
272  PainterStateSaver stateSaver(painter);
273 
274  if (!unread.isEmpty()) {
275  QFont font = painter->font();
276  font.setBold(true);
277  painter->setFont(font);
278  }
279 
280  const QColor unreadColor = (option.state & QStyle::State_Selected) ? d->mSelectedUnreadColor : d->mDeselectedUnreadColor;
281  const QRect iconRect = s->subElementRect(QStyle::SE_ItemViewItemDecoration, &option4, widget);
282 
283  if (option.decorationPosition == QStyleOptionViewItem::Left ||
284  option.decorationPosition == QStyleOptionViewItem::Right) {
285  // Squeeze the folder text if it is to big and calculate the rectangles
286  // where the folder text and the unread count will be drawn to
287  QString folderName = text;
288  QFontMetrics fm(painter->fontMetrics());
289  const int unreadWidth = fm.width(unread);
290  int folderWidth(fm.width(folderName));
291  const bool enoughPlaceForText = (option.rect.width() > (folderWidth + unreadWidth + iconRect.width()));
292 
293  if (!enoughPlaceForText && (folderWidth + unreadWidth > textRect.width())) {
294  folderName = fm.elidedText(folderName, Qt::ElideRight,
295  option.rect.width() - unreadWidth - iconRect.width());
296  folderWidth = fm.width(folderName);
297  }
298  QRect folderRect = textRect;
299  QRect unreadRect = textRect;
300  folderRect.setRight(textRect.left() + folderWidth);
301  unreadRect = QRect(folderRect.right(), folderRect.top(), unreadRect.width(), unreadRect.height());
302  if (textColor.isValid()) {
303  painter->setPen(textColor);
304  }
305 
306  // Draw folder name and unread count
307  painter->drawText(folderRect, Qt::AlignLeft | Qt::AlignVCenter, folderName);
308  painter->setPen(unreadColor);
309  painter->drawText(unreadRect, Qt::AlignLeft | Qt::AlignVCenter, unread);
310  } else if (option.decorationPosition == QStyleOptionViewItem::Top) {
311  if (unreadCount > 0) {
312  // draw over the icon
313  painter->setPen(unreadColor);
314  painter->drawText(iconRect, Qt::AlignCenter, QString::number(unreadCount));
315  }
316  }
317  return;
318  }
319 
320  // For the unread/total column, paint the summed up count if the item
321  // is collapsed
322  if ((index.column() == 1 || index.column() == 2)) {
323 
324  QFont savedFont = painter->font();
325  QString sumText;
326  if (index.column() == 1 && ((!expanded && unreadRecursiveCount > 0) || (expanded && unreadCount > 0))) {
327  QFont font = painter->font();
328  font.setBold(true);
329  painter->setFont(font);
330  sumText = QString::number(expanded ? unreadCount : unreadRecursiveCount);
331  } else {
332 
333  qint64 totalCount = statistics.count();
334  if (index.column() == 2 && ((!expanded && totalRecursiveCount > 0) || (expanded && totalCount > 0))) {
335  sumText = QString::number(expanded ? totalCount : totalRecursiveCount);
336  }
337  }
338 
339  painter->drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, sumText);
340  painter->setFont(savedFont);
341  return;
342  }
343 
344  //total size
345  if (index.column() == 3 && !expanded) {
346  if (textColor.isValid()) {
347  painter->setPen(textColor);
348  }
349  painter->drawText(textRect, option4.displayAlignment | Qt::AlignVCenter, KIO::convertSize((KIO::filesize_t)totalSize));
350  return;
351  }
352 
353  if (textColor.isValid()) {
354  painter->setPen(textColor);
355  }
356  painter->drawText(textRect, option4.displayAlignment | Qt::AlignVCenter, text);
357 }
358 
359 void CollectionStatisticsDelegate::updatePalette()
360 {
361  Q_D(CollectionStatisticsDelegate);
362  d->updateColor();
363 }
Akonadi::CollectionStatisticsDelegate::~CollectionStatisticsDelegate
~CollectionStatisticsDelegate()
Destroys the collection statistics delegate.
Definition: collectionstatisticsdelegate.cpp:111
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
QModelIndex
QWidget
QAbstractItemModel::rowCount
virtual int rowCount(const QModelIndex &parent) const =0
QAbstractItemModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
Akonadi::CollectionStatisticsDelegate::setProgressAnimationEnabled
void setProgressAnimationEnabled(bool enable)
Definition: collectionstatisticsdelegate.cpp:128
QAbstractItemView
QRect::right
int right() const
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:351
QStyledItemDelegate::initStyleOption
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
QPainter::font
const QFont & font() const
QFont
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
Akonadi::CollectionStatisticsDelegate::updatePalette
void updatePalette()
Definition: collectionstatisticsdelegate.cpp:359
QPainter::save
void save()
QVariant::value
T value() const
QRect::height
int height() const
QFontMetrics
QFont::setBold
void setBold(bool enable)
QRect
QPainter::setFont
void setFont(const QFont &font)
QString::number
QString number(int n, int base)
QVariant::toInt
int toInt(bool *ok) const
QRect::top
int top() const
QStyleOptionViewItem
QStyle
QPainter::setPen
void setPen(const QColor &color)
QStyledItemDelegate::paint
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
QRect::left
int left() const
QPainter
QString::isEmpty
bool isEmpty() const
QModelIndex::row
int row() const
Akonadi::CollectionStatisticsDelegate::initStyleOption
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
Definition: collectionstatisticsdelegate.cpp:150
QPainter::drawText
void drawText(const QPointF &position, const QString &text)
Akonadi::EntityTreeModel::CollectionRole
The collection.
Definition: entitytreemodel.h:336
QString
QColor
QTreeView::isExpanded
bool isExpanded(const QModelIndex &index) const
Akonadi::CollectionStatisticsDelegate::unreadCountShown
bool unreadCountShown() const
Returns whether the unread count is drawn next to the folder name.
Definition: collectionstatisticsdelegate.cpp:122
Akonadi::CollectionStatisticsDelegate::CollectionStatisticsDelegate
CollectionStatisticsDelegate(QAbstractItemView *parent)
Creates a new collection statistics delegate.
Definition: collectionstatisticsdelegate.cpp:97
QFontMetrics::width
int width(const QString &text, int len) const
QRect::setRight
void setRight(int x)
Akonadi::CollectionStatisticsDelegate::paint
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
Definition: collectionstatisticsdelegate.cpp:196
QRect::width
int width() const
QModelIndex::model
const QAbstractItemModel * model() const
Akonadi::CollectionStatisticsDelegate::setUnreadCountShown
void setUnreadCountShown(bool enable)
Sets whether the unread count is drawn next to the folder name.
Definition: collectionstatisticsdelegate.cpp:116
QModelIndex::data
QVariant data(int role) const
QTreeView
QAbstractItemModel::hasChildren
virtual bool hasChildren(const QModelIndex &parent) const
QModelIndex::sibling
QModelIndex sibling(int row, int column) const
QPainter::fontMetrics
QFontMetrics fontMetrics() const
Akonadi::EntityTreeModel::FetchingState
There is a fetch of items in this collection in progress.
Definition: entitytreemodel.h:376
QModelIndex::column
int column() const
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
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QVariant::isValid
bool isValid() const
QStyle::subElementRect
virtual QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const =0
QStyleOptionViewItemV4
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
QObject::parent
QObject * parent() const
Akonadi::CollectionStatisticsDelegate
A delegate that draws unread and total count for CollectionStatisticsModel.
Definition: collectionstatisticsdelegate.h:64
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Akonadi::Collection::statistics
CollectionStatistics statistics() const
Returns the collection statistics of the collection.
Definition: collection.cpp:238
QColor::isValid
bool isValid() const
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
QVariant
QStyledItemDelegate
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:02 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
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2

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