Akonadi

progressspinnerdelegate.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB,
3 a KDAB Group company, info@kdab.net
4 SPDX-FileContributor: Stephen Kelly <stephen@kdab.com>
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 <KPixmapSequenceLoader>
14
15#include <QAbstractItemView>
16#include <QTimerEvent>
17
18using namespace Akonadi;
19
20DelegateAnimator::DelegateAnimator(QAbstractItemView *view)
21 : QObject(view)
22 , m_view(view)
23 , m_pixmapSequence(KPixmapSequenceLoader::load(QStringLiteral("process-working"), 22))
24{
25}
26
27void 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
35void 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
45void DelegateAnimator::timerEvent(QTimerEvent *event)
46{
47 if (!(event->timerId() == m_timerId && m_view)) {
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);
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
75QPixmap 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
85ProgressSpinnerDelegate::ProgressSpinnerDelegate(DelegateAnimator *animator, QObject *parent)
86 : QStyledItemDelegate(parent)
87 , m_animator(animator)
88{
89}
90
91void ProgressSpinnerDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
92{
94
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
108size_t Akonadi::qHash(const Akonadi::DelegateAnimator::Animation &anim, size_t seed) noexcept
109{
110 return qHash(anim.index, seed);
111}
112
113#include "moc_progressspinnerdelegate_p.cpp"
@ FetchingState
There is a fetch of items in this collection in progress.
@ FetchStateRole
Returns the FetchState of a particular item.
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
Helper integration between Akonadi and Qt.
QAction * load(const QObject *recvr, const char *slot, QObject *parent)
KTEXTEDITOR_EXPORT size_t qHash(KTextEditor::Cursor cursor, size_t seed=0) noexcept
QVariant data(int role) const const
virtual void timerEvent(QTimerEvent *event)
bool isEmpty() const const
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const const
void * data()
bool isValid() const const
int toInt(bool *ok) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:01:42 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.