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

KIO

  • sources
  • kde-4.14
  • kdelibs
  • kio
  • kio
delegateanimationhandler.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the KDE project
3 
4  Copyright © 2007 Fredrik Höglund <fredrik@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "delegateanimationhandler_p.h"
23 
24 #include <QListView>
25 #include <QAbstractItemView>
26 #include <QPersistentModelIndex>
27 #include <QTime>
28 #include <QDebug>
29 
30 #include <cmath>
31 #include "kdirmodel.h"
32 #include <kdebug.h>
33 #include <qabstractproxymodel.h>
34 
35 #include "delegateanimationhandler_p.moc"
36 
37 namespace KIO
38 {
39 
40 // Needed because state() is a protected method
41 class ProtectedAccessor : public QAbstractItemView
42 {
43 public:
44  bool draggingState() const { return state() == DraggingState; }
45 };
46 
47 // Debug output is disabled by default, use kdebugdialog to enable it
48 static int animationDebugArea() { static int s_area = KDebug::registerArea("kio (delegateanimationhandler)", false);
49  return s_area; }
50 
51 // ---------------------------------------------------------------------------
52 
53 
54 
55 CachedRendering::CachedRendering(QStyle::State state, const QSize &size, QModelIndex index)
56  : state(state), regular(QPixmap(size)), hover(QPixmap(size)), valid(true), validityIndex(index)
57 {
58  regular.fill(Qt::transparent);
59  hover.fill(Qt::transparent);
60 
61  if (index.model())
62  {
63  connect(index.model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
64  SLOT(dataChanged(QModelIndex,QModelIndex)));
65  connect(index.model(), SIGNAL(modelReset()), SLOT(modelReset()));
66  }
67 }
68 
69 void CachedRendering::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight)
70 {
71  if (validityIndex.row() >= topLeft.row() && validityIndex.column() >= topLeft.column() &&
72  validityIndex.row() <= bottomRight.row() && validityIndex.column() <= bottomRight.column())
73  valid = false;
74 }
75 
76 void CachedRendering::modelReset()
77 {
78  valid = false;
79 }
80 
81 // ---------------------------------------------------------------------------
82 
83 
84 
85 AnimationState::AnimationState(const QModelIndex &index)
86  : index(index), direction(QTimeLine::Forward),
87  animating(false), jobAnimation(false), progress(0.0), m_fadeProgress(1.0),
88  m_jobAnimationAngle(0.0), renderCache(NULL), fadeFromRenderCache(NULL)
89 {
90  creationTime.start();
91 }
92 
93 
94 AnimationState::~AnimationState()
95 {
96  delete renderCache;
97  delete fadeFromRenderCache;
98 }
99 
100 
101 bool AnimationState::update()
102 {
103  const qreal runtime = (direction == QTimeLine::Forward ? 150 : 250); // milliseconds
104  const qreal increment = 1000. / runtime / 1000.;
105  const qreal delta = increment * time.restart();
106 
107  if (direction == QTimeLine::Forward)
108  {
109  progress = qMin(qreal(1.0), progress + delta);
110  animating = (progress < 1.0);
111  }
112  else
113  {
114  progress = qMax(qreal(0.0), progress - delta);
115  animating = (progress > 0.0);
116  }
117 
118 
119  if (fadeFromRenderCache)
120  {
121  //Icon fading goes always forwards
122  m_fadeProgress = qMin(qreal(1.0), m_fadeProgress + delta);
123  animating |= (m_fadeProgress < 1.0);
124  if (m_fadeProgress == 1)
125  setCachedRenderingFadeFrom(0);
126  }
127 
128  if (jobAnimation)
129  {
130  m_jobAnimationAngle += 1.0;
131  if (m_jobAnimationAngle == 360)
132  m_jobAnimationAngle = 0;
133 
134  if (index.model()->data(index, KDirModel::HasJobRole).toBool())
135  {
136  animating = true;
137  //there is a job here still...
138  return false;
139  }
140  else
141  {
142  animating = false;
143  //there's no job here anymore, return true so we stop painting this.
144  return true;
145  }
146  }
147  else
148  {
149  return !animating;
150  }
151 }
152 
153 qreal AnimationState::hoverProgress() const
154 {
155 #ifndef M_PI_2
156 #define M_PI_2 1.57079632679489661923
157 #endif
158  return qRound(255.0 * std::sin(progress * M_PI_2)) / 255.0;
159 }
160 
161 qreal AnimationState::fadeProgress() const
162 {
163  return qRound(255.0 * std::sin(m_fadeProgress * M_PI_2)) / 255.0;
164 }
165 
166 qreal AnimationState::jobAnimationAngle() const
167 {
168  return m_jobAnimationAngle;
169 }
170 
171 bool AnimationState::hasJobAnimation() const
172 {
173  return jobAnimation;
174 }
175 
176 void AnimationState::setJobAnimation(bool value)
177 {
178  jobAnimation = value;
179 }
180 
181 // ---------------------------------------------------------------------------
182 
183 static const int switchIconInterval = 1000;
184 
185 DelegateAnimationHandler::DelegateAnimationHandler(QObject *parent)
186  : QObject(parent)
187 {
188  iconSequenceTimer.setSingleShot(true);
189  iconSequenceTimer.setInterval(switchIconInterval);
190  connect(&iconSequenceTimer, SIGNAL(timeout()), SLOT(sequenceTimerTimeout()));;
191 }
192 
193 DelegateAnimationHandler::~DelegateAnimationHandler()
194 {
195  timer.stop();
196 
197  QMapIterator<const QAbstractItemView*, AnimationList*> i(animationLists);
198  while (i.hasNext())
199  {
200  i.next();
201  qDeleteAll(*i.value());
202  delete i.value();
203  }
204  animationLists.clear();
205 }
206 
207 void DelegateAnimationHandler::sequenceTimerTimeout()
208 {
209  QAbstractItemModel* model = const_cast<QAbstractItemModel*>(sequenceModelIndex.model());
210  QAbstractProxyModel* proxy = qobject_cast<QAbstractProxyModel*>(model);
211  QModelIndex index = sequenceModelIndex;
212 
213  if (proxy)
214  {
215  index = proxy->mapToSource(index);
216  model = proxy->sourceModel();
217  }
218 
219  KDirModel* dirModel = dynamic_cast<KDirModel*>(model);
220  if (dirModel)
221  {
222  kDebug(animationDebugArea()) << "requesting" << currentSequenceIndex;
223  dirModel->requestSequenceIcon(index, currentSequenceIndex);
224  iconSequenceTimer.start(); // Some upper-bound interval is needed, in case items are not generated
225  }
226 }
227 
228 void DelegateAnimationHandler::gotNewIcon(const QModelIndex& index)
229 {
230  Q_UNUSED(index);
231 
232  kDebug(animationDebugArea()) << currentSequenceIndex;
233  if (sequenceModelIndex.isValid() && currentSequenceIndex)
234  iconSequenceTimer.start();
235 // if(index ==sequenceModelIndex) //Leads to problems
236  ++currentSequenceIndex;
237 }
238 
239 void DelegateAnimationHandler::setSequenceIndex(int sequenceIndex)
240 {
241  kDebug(animationDebugArea()) << sequenceIndex;
242 
243  if (sequenceIndex > 0)
244  {
245  currentSequenceIndex = sequenceIndex;
246  iconSequenceTimer.start();
247  }
248  else
249  {
250  currentSequenceIndex = 0;
251  sequenceTimerTimeout(); //Set the icon back to the standard one
252  currentSequenceIndex = 0; //currentSequenceIndex was incremented, set it back to 0
253  iconSequenceTimer.stop();
254  }
255 }
256 
257 void DelegateAnimationHandler::eventuallyStartIteration(QModelIndex index)
258 {
259 // if (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) {
261 
262  if (sequenceModelIndex.isValid())
263  setSequenceIndex(0); // Stop old iteration, and reset the icon for the old iteration
264 
265  // Start sequence iteration
266  sequenceModelIndex = index;
267  setSequenceIndex(1);
268 // }
269 }
270 
271 AnimationState *DelegateAnimationHandler::animationState(const QStyleOption &option,
272  const QModelIndex &index,
273  const QAbstractItemView *view)
274 {
275  // We can't do animations reliably when an item is being dragged, since that
276  // item will be drawn in two locations at the same time and hovered in one and
277  // not the other. We can't tell them apart because they both have the same index.
278  if (!view || static_cast<const ProtectedAccessor*>(view)->draggingState())
279  return NULL;
280 
281  AnimationState *state = findAnimationState(view, index);
282  bool hover = option.state & QStyle::State_MouseOver;
283 
284  // If the cursor has entered an item
285  if (!state && hover)
286  {
287  state = new AnimationState(index);
288  addAnimationState(state, view);
289 
290  if (!fadeInAddTime.isValid() ||
291  (fadeInAddTime.isValid() && fadeInAddTime.elapsed() > 300))
292  {
293  startAnimation(state);
294  }
295  else
296  {
297  state->animating = false;
298  state->progress = 1.0;
299  state->direction = QTimeLine::Forward;
300  }
301 
302  fadeInAddTime.restart();
303 
304  eventuallyStartIteration(index);
305  }
306  else if (state)
307  {
308  // If the cursor has exited an item
309  if (!hover && (!state->animating || state->direction == QTimeLine::Forward))
310  {
311  state->direction = QTimeLine::Backward;
312 
313  if (state->creationTime.elapsed() < 200)
314  state->progress = 0.0;
315 
316  startAnimation(state);
317 
318  // Stop sequence iteration
319  if (index == sequenceModelIndex)
320  {
321  setSequenceIndex(0);
322  sequenceModelIndex = QPersistentModelIndex();
323  }
324  }
325  else if (hover && state->direction == QTimeLine::Backward)
326  {
327  // This is needed to handle the case where an item is dragged within
328  // the view, and dropped in a different location. State_MouseOver will
329  // initially not be set causing a "hover out" animation to start.
330  // This reverses the direction as soon as we see the bit being set.
331  state->direction = QTimeLine::Forward;
332 
333  if (!state->animating)
334  startAnimation(state);
335 
336  eventuallyStartIteration(index);
337  }
338  }
339  else if (!state && index.model()->data(index, KDirModel::HasJobRole).toBool())
340  {
341  state = new AnimationState(index);
342  addAnimationState(state, view);
343  startAnimation(state);
344  state->setJobAnimation(true);
345  }
346 
347  return state;
348 }
349 
350 
351 AnimationState *DelegateAnimationHandler::findAnimationState(const QAbstractItemView *view,
352  const QModelIndex &index) const
353 {
354  // Try to find a list of animation states for the view
355  AnimationList *list = animationLists.value(view);
356 
357  if (list)
358  {
359  foreach (AnimationState *state, *list)
360  if (state->index == index)
361  return state;
362  }
363 
364  return NULL;
365 }
366 
367 
368 void DelegateAnimationHandler::addAnimationState(AnimationState *state, const QAbstractItemView *view)
369 {
370  AnimationList *list = animationLists.value(view);
371 
372  // If this is the first time we've seen this view
373  if (!list)
374  {
375  connect(view, SIGNAL(destroyed(QObject*)), SLOT(viewDeleted(QObject*)));
376 
377  list = new AnimationList;
378  animationLists.insert(view, list);
379  }
380 
381  list->append(state);
382 }
383 
384 void DelegateAnimationHandler::restartAnimation(AnimationState *state)
385 {
386  startAnimation(state);
387 }
388 
389 void DelegateAnimationHandler::startAnimation(AnimationState *state)
390 {
391  state->time.start();
392  state->animating = true;
393 
394  if (!timer.isActive())
395  timer.start(1000 / 30, this); // 30 fps
396 }
397 
398 int DelegateAnimationHandler::runAnimations(AnimationList *list, const QAbstractItemView *view)
399 {
400  int activeAnimations = 0;
401  QRegion region;
402 
403  QMutableLinkedListIterator<AnimationState*> i(*list);
404  while (i.hasNext())
405  {
406  AnimationState *state = i.next();
407 
408  if (!state->animating)
409  continue;
410 
411  // We need to make sure the index is still valid, since it could be removed
412  // while the animation is running.
413  if (state->index.isValid())
414  {
415  bool finished = state->update();
416  region += view->visualRect(state->index);
417 
418  if (!finished)
419  {
420  activeAnimations++;
421  continue;
422  }
423  }
424 
425  // If the direction is Forward, the state object needs to stick around
426  // after the animation has finished, so we know that we've already done
427  // a "hover in" for the index.
428  if (state->direction == QTimeLine::Backward || !state->index.isValid())
429  {
430  delete state;
431  i.remove();
432  }
433  }
434 
435  // Trigger a repaint of the animated indexes
436  if (!region.isEmpty())
437  const_cast<QAbstractItemView*>(view)->viewport()->update(region);
438 
439  return activeAnimations;
440 }
441 
442 
443 void DelegateAnimationHandler::viewDeleted(QObject *view)
444 {
445  AnimationList *list = animationLists.take(static_cast<QAbstractItemView*>(view));
446  qDeleteAll(*list);
447  delete list;
448 }
449 
450 
451 void DelegateAnimationHandler::timerEvent(QTimerEvent *)
452 {
453  int activeAnimations = 0;
454 
455  AnimationListsIterator i(animationLists);
456  while (i.hasNext())
457  {
458  i.next();
459  AnimationList *list = i.value();
460  const QAbstractItemView *view = i.key();
461 
462  activeAnimations += runAnimations(list, view);
463  }
464 
465  if (activeAnimations == 0 && timer.isActive())
466  timer.stop();
467 }
468 
469 }
470 
delegateanimationhandler_p.h
QTimer::setInterval
void setInterval(int msec)
QModelIndex
KIO::animationDebugArea
static int animationDebugArea()
Definition: delegateanimationhandler.cpp:48
kdebug.h
QAbstractItemView
QPixmap::fill
void fill(const QColor &color)
QAbstractProxyModel
KIO::AnimationState::hoverProgress
qreal hoverProgress() const
Definition: delegateanimationhandler.cpp:153
QBasicTimer::stop
void stop()
timeout
int timeout
QBasicTimer::start
void start(int msec, QObject *object)
QPersistentModelIndex::column
int column() const
KIO::CachedRendering::CachedRendering
CachedRendering(QStyle::State state, const QSize &size, QModelIndex validityIndex)
Definition: delegateanimationhandler.cpp:55
QTime::isValid
bool isValid() const
M_PI_2
#define M_PI_2
KDirModel::HasJobRole
returns whether or not there is a job on an item (file/directory)
Definition: kdirmodel.h:139
QStyle::State
typedef State
KIO::DelegateAnimationHandler::restartAnimation
void restartAnimation(AnimationState *state)
Definition: delegateanimationhandler.cpp:384
QPersistentModelIndex::model
const QAbstractItemModel * model() const
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KIO::DelegateAnimationHandler::gotNewIcon
void gotNewIcon(const QModelIndex &index)
Definition: delegateanimationhandler.cpp:228
KIO::AnimationState::jobAnimationAngle
qreal jobAnimationAngle() const
Definition: delegateanimationhandler.cpp:166
KIO::CachedRendering::regular
QPixmap regular
Definition: delegateanimationhandler_p.h:49
KIO::AnimationState
Definition: delegateanimationhandler_p.h:60
KDirModel::requestSequenceIcon
void requestSequenceIcon(const QModelIndex &index, int sequenceIndex)
This emits the needSequenceIcon signal, requesting another sequence icon.
Definition: kdirmodel.cpp:855
KIO::CachedRendering::hover
QPixmap hover
Definition: delegateanimationhandler_p.h:50
KIO::AnimationState::~AnimationState
~AnimationState()
Definition: delegateanimationhandler.cpp:94
KIO::AnimationState::hasJobAnimation
bool hasJobAnimation() const
Definition: delegateanimationhandler.cpp:171
QTimerEvent
QStyleOption
QTime::elapsed
int elapsed() const
QPersistentModelIndex::isValid
bool isValid() const
QMapIterator
QBasicTimer::isActive
bool isActive() const
QMapIterator::next
Item next()
QObject
KIO::CachedRendering::validityIndex
QPersistentModelIndex validityIndex
Definition: delegateanimationhandler_p.h:53
KIO::DelegateAnimationHandler::~DelegateAnimationHandler
~DelegateAnimationHandler()
Definition: delegateanimationhandler.cpp:193
QModelIndex::row
int row() const
KDebug::registerArea
static int registerArea(const QByteArray &areaName, bool enabled=true)
QTime::restart
int restart()
KIO::CachedRendering::valid
bool valid
Definition: delegateanimationhandler_p.h:52
QAbstractItemModel::data
virtual QVariant data(const QModelIndex &index, int role) const =0
QMutableLinkedListIterator
QMapIterator::value
const T & value() const
KIO::AnimationState::fadeProgress
qreal fadeProgress() const
Definition: delegateanimationhandler.cpp:161
QPixmap
QSize
QTimer::stop
void stop()
QAbstractItemView::visualRect
virtual QRect visualRect(const QModelIndex &index) const =0
Forward
KIO::DelegateAnimationHandler::animationState
AnimationState * animationState(const QStyleOption &option, const QModelIndex &index, const QAbstractItemView *view)
Definition: delegateanimationhandler.cpp:271
QAbstractItemView::state
State state() const
kdirmodel.h
QPersistentModelIndex
QAbstractProxyModel::sourceModel
QAbstractItemModel * sourceModel() const
QModelIndex::model
const QAbstractItemModel * model() const
KIO::switchIconInterval
static const int switchIconInterval
Definition: delegateanimationhandler.cpp:183
KIO::AnimationState::setJobAnimation
void setJobAnimation(bool value)
Definition: delegateanimationhandler.cpp:176
QTimeLine
QModelIndex::column
int column() const
QVariant::toBool
bool toBool() const
KIO::AnimationState::setCachedRenderingFadeFrom
void setCachedRenderingFadeFrom(CachedRendering *rendering)
Definition: delegateanimationhandler_p.h:84
QAbstractItemModel
QRegion::isEmpty
bool isEmpty() const
KIO::DelegateAnimationHandler::DelegateAnimationHandler
DelegateAnimationHandler(QObject *parent=0)
Definition: delegateanimationhandler.cpp:185
QTimer::start
void start(int msec)
QTime::start
void start()
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QAbstractProxyModel::mapToSource
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const =0
KDirModel
A model for a KIO-based directory tree.
Definition: kdirmodel.h:48
QObject::destroyed
void destroyed(QObject *obj)
QPersistentModelIndex::row
int row() const
QRegion
QMapIterator::hasNext
bool hasNext() const
KRecentDirs::list
QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
Definition: krecentdirs.cpp:60
QTimer::setSingleShot
void setSingleShot(bool singleShot)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:24:52 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

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