• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 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
40using namespace Akonadi;
41
42namespace Akonadi {
43
44enum CountType {
45 UnreadCount,
46 TotalCount
47};
48
49class CollectionStatisticsDelegatePrivate
50{
51public:
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
97CollectionStatisticsDelegate::CollectionStatisticsDelegate(QAbstractItemView *parent)
98 : QStyledItemDelegate(parent)
99 , d_ptr(new CollectionStatisticsDelegatePrivate(parent))
100{
101
102}
103
104CollectionStatisticsDelegate::CollectionStatisticsDelegate(QTreeView *parent)
105 : QStyledItemDelegate(parent)
106 , d_ptr(new CollectionStatisticsDelegatePrivate(parent))
107{
108
109}
110
111CollectionStatisticsDelegate::~CollectionStatisticsDelegate()
112{
113 delete d_ptr;
114}
115
116void CollectionStatisticsDelegate::setUnreadCountShown(bool enable)
117{
118 Q_D(CollectionStatisticsDelegate);
119 d->drawUnreadAfterFolder = enable;
120}
121
122bool CollectionStatisticsDelegate::unreadCountShown() const
123{
124 Q_D(const CollectionStatisticsDelegate);
125 return d->drawUnreadAfterFolder;
126}
127
128void 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
144bool CollectionStatisticsDelegate::progressAnimationEnabled() const
145{
146 Q_D(const CollectionStatisticsDelegate);
147 return d->animator != 0;
148}
149
150void 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
178class PainterStateSaver
179{
180public:
181 PainterStateSaver(QPainter *painter)
182 {
183 mPainter = painter;
184 mPainter->save();
185 }
186
187 ~PainterStateSaver()
188 {
189 mPainter->restore();
190 }
191
192private:
193 QPainter *mPainter;
194};
195
196void 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
359void CollectionStatisticsDelegate::updatePalette()
360{
361 Q_D(CollectionStatisticsDelegate);
362 d->updateColor();
363}
Akonadi::CollectionStatisticsDelegate
A delegate that draws unread and total count for CollectionStatisticsModel.
Definition collectionstatisticsdelegate.h:65
Akonadi::CollectionStatisticsDelegate::paint
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
Definition collectionstatisticsdelegate.cpp:196
Akonadi::CollectionStatisticsDelegate::updatePalette
void updatePalette()
Definition collectionstatisticsdelegate.cpp:359
Akonadi::CollectionStatisticsDelegate::initStyleOption
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
Definition collectionstatisticsdelegate.cpp:150
Akonadi::CollectionStatisticsDelegate::unreadCountShown
bool unreadCountShown() const
Returns whether the unread count is drawn next to the folder name.
Definition collectionstatisticsdelegate.cpp:122
Akonadi::CollectionStatisticsDelegate::setUnreadCountShown
void setUnreadCountShown(bool enable)
Sets whether the unread count is drawn next to the folder name.
Definition collectionstatisticsdelegate.cpp:116
Akonadi::CollectionStatisticsDelegate::~CollectionStatisticsDelegate
~CollectionStatisticsDelegate()
Destroys the collection statistics delegate.
Definition collectionstatisticsdelegate.cpp:111
Akonadi::CollectionStatisticsDelegate::setProgressAnimationEnabled
void setProgressAnimationEnabled(bool enable)
Definition collectionstatisticsdelegate.cpp:128
Akonadi::CollectionStatisticsDelegate::CollectionStatisticsDelegate
CollectionStatisticsDelegate(QAbstractItemView *parent)
Creates a new collection statistics delegate.
Definition collectionstatisticsdelegate.cpp:97
Akonadi::CollectionStatistics
Provides statistics information of a Collection.
Definition collectionstatistics.h:70
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::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::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
Akonadi::Collection
Represents a collection of PIM items.
Definition collection.h:76
Akonadi::EntityTreeModel::FetchingState
@ FetchingState
There is a fetch of items in this collection in progress.
Definition entitytreemodel.h:376
Akonadi::EntityTreeModel::CollectionRole
@ CollectionRole
The collection.
Definition entitytreemodel.h:336
Akonadi::EntityTreeModel::FetchStateRole
@ FetchStateRole
Returns the FetchState of a particular item.
Definition entitytreemodel.h:351
Akonadi
FreeBusyManager::Singleton.
Definition actionstatemanager_p.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Jan 24 2024 00:00:00 by doxygen 1.10.0 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
  • Related Pages

kdepimlibs-4.14.10 API Reference

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