Akonadi

progressspinnerdelegate.cpp
1 /*
2  SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB,
3  a KDAB Group company, [email protected]
4  SPDX-FileContributor: Stephen Kelly <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "progressspinnerdelegate_p.h"
10 
11 #include "entitytreemodel.h"
12 
13 #include <KIconLoader>
14 
15 #include <QAbstractItemView>
16 #include <QTimerEvent>
17 
18 using namespace Akonadi;
19 
20 DelegateAnimator::DelegateAnimator(QAbstractItemView *view)
21  : QObject(view)
22  , m_view(view)
23  , m_pixmapSequence(KIconLoader::global()->loadPixmapSequence(QStringLiteral("process-working"), 22))
24 {
25 }
26 
27 void DelegateAnimator::push(const QModelIndex &index)
28 {
29  if (m_animations.isEmpty()) {
30  m_timerId = startTimer(200);
31  }
32  m_animations.insert(Animation(index));
33 }
34 
35 void DelegateAnimator::pop(const QModelIndex &index)
36 {
37  if (m_animations.remove(Animation(index))) {
38  if (m_animations.isEmpty() && m_timerId != -1) {
39  killTimer(m_timerId);
40  m_timerId = -1;
41  }
42  }
43 }
44 
45 void DelegateAnimator::timerEvent(QTimerEvent *event)
46 {
47  if (!(event->timerId() == m_timerId && m_view)) {
48  QObject::timerEvent(event);
49  return;
50  }
51 
52  QRegion region;
53  // working copy as m_animations could be modified in the loop by pop()
54  const QSet<Animation> currentAnimations(m_animations);
55  for (const Animation &animation : currentAnimations) {
56  // Check if loading is finished (we might not be notified, if the index is scrolled out of view)
57  const QVariant fetchState = animation.index.data(Akonadi::EntityTreeModel::FetchStateRole);
58  if (fetchState.toInt() != Akonadi::EntityTreeModel::FetchingState) {
59  pop(animation.index);
60  continue;
61  }
62 
63  // This repaints the entire delegate (icon and text).
64  // TODO: See if there's a way to repaint only part of it (the icon).
65  animation.nextFrame();
66  const QRect rect = m_view->visualRect(animation.index);
67  region += rect;
68  }
69 
70  if (!region.isEmpty()) {
71  m_view->viewport()->update(region);
72  }
73 }
74 
75 QPixmap DelegateAnimator::sequenceFrame(const QModelIndex &index)
76 {
77  for (const Animation &animation : std::as_const(m_animations)) {
78  if (animation.index == index) {
79  return m_pixmapSequence.frameAt(animation.frame);
80  }
81  }
82  return QPixmap();
83 }
84 
85 ProgressSpinnerDelegate::ProgressSpinnerDelegate(DelegateAnimator *animator, QObject *parent)
86  : QStyledItemDelegate(parent)
87  , m_animator(animator)
88 {
89 }
90 
91 void ProgressSpinnerDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
92 {
94 
95  const QVariant fetchState = index.data(Akonadi::EntityTreeModel::FetchStateRole);
96  if (!fetchState.isValid() || fetchState.toInt() != Akonadi::EntityTreeModel::FetchingState) {
97  m_animator->pop(index);
98  return;
99  }
100 
101  m_animator->push(index);
102 
103  if (auto v = qstyleoption_cast<QStyleOptionViewItem *>(option)) {
104  v->icon = m_animator->sequenceFrame(index);
105  }
106 }
107 
108 uint Akonadi::qHash(const Akonadi::DelegateAnimator::Animation &anim)
109 {
110  return qHash(anim.index);
111 }
bool isValid() const const
virtual void timerEvent(QTimerEvent *event)
QVariant data(int role) const const
int toInt(bool *ok) const const
KCALENDARCORE_EXPORT uint qHash(const KCalendarCore::Period &key)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const const
@ FetchingState
There is a fetch of items in this collection in progress.
@ FetchStateRole
Returns the FetchState of a particular item.
Helper integration between Akonadi and Qt.
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 03:52:16 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.