KIO
delegateanimationhandler.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "delegateanimationhandler_p.h"
00023
00024 #include <QListView>
00025 #include <QAbstractItemView>
00026 #include <QPersistentModelIndex>
00027 #include <QTime>
00028 #include <QDebug>
00029
00030 #include <cmath>
00031 #include "kdirmodel.h"
00032 #include <kglobalsettings.h>
00033 #include <kdebug.h>
00034 #include <qabstractproxymodel.h>
00035
00036 #include "delegateanimationhandler_p.moc"
00037
00038 namespace KIO
00039 {
00040
00041
00042 class ProtectedAccessor : public QAbstractItemView
00043 {
00044 public:
00045 bool draggingState() const { return state() == DraggingState; }
00046 };
00047
00048
00049
00050
00051
00052
00053
00054 CachedRendering::CachedRendering(QStyle::State state, const QSize &size, QModelIndex index)
00055 : state(state), regular(QPixmap(size)), hover(QPixmap(size)), valid(true), validityIndex(index)
00056 {
00057 regular.fill(Qt::transparent);
00058 hover.fill(Qt::transparent);
00059
00060 if (index.model())
00061 {
00062 connect(index.model(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
00063 SLOT(dataChanged(const QModelIndex &, const QModelIndex &)));
00064 connect(index.model(), SIGNAL(modelReset()), SLOT(modelReset()));
00065 }
00066 }
00067
00068 void CachedRendering::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight)
00069 {
00070 if (validityIndex.row() >= topLeft.row() && validityIndex.column() >= topLeft.column() &&
00071 validityIndex.row() <= bottomRight.row() && validityIndex.column() <= bottomRight.column())
00072 valid = false;
00073 }
00074
00075 void CachedRendering::modelReset()
00076 {
00077 valid = false;
00078 }
00079
00080
00081
00082
00083
00084 AnimationState::AnimationState(const QModelIndex &index)
00085 : index(index), direction(QTimeLine::Forward),
00086 animating(false), progress(0.0), m_fadeProgress(1.0), renderCache(NULL), fadeFromRenderCache(NULL)
00087 {
00088 creationTime.start();
00089 }
00090
00091
00092 AnimationState::~AnimationState()
00093 {
00094 delete renderCache;
00095 delete fadeFromRenderCache;
00096 }
00097
00098
00099 bool AnimationState::update()
00100 {
00101 const qreal runtime = (direction == QTimeLine::Forward ? 150 : 250);
00102 const qreal increment = 1000. / runtime / 1000.;
00103 const qreal delta = increment * time.restart();
00104
00105 if (direction == QTimeLine::Forward)
00106 {
00107 progress = qMin(qreal(1.0), progress + delta);
00108 animating = (progress < 1.0);
00109 }
00110 else
00111 {
00112 progress = qMax(qreal(0.0), progress - delta);
00113 animating = (progress > 0.0);
00114 }
00115
00116
00117 if (fadeFromRenderCache)
00118 {
00119
00120 m_fadeProgress = qMin(qreal(1.0), m_fadeProgress + delta);
00121 animating |= (m_fadeProgress < 1.0);
00122 if (m_fadeProgress == 1)
00123 setCachedRenderingFadeFrom(0);
00124 }
00125
00126 return !animating;
00127 }
00128
00129
00130 qreal AnimationState::hoverProgress() const
00131 {
00132 #ifndef M_PI_2
00133 #define M_PI_2 1.57079632679489661923
00134 #endif
00135 return qRound(255.0 * std::sin(progress * M_PI_2)) / 255.0;
00136 }
00137
00138 qreal AnimationState::fadeProgress() const
00139 {
00140 return qRound(255.0 * std::sin(m_fadeProgress * M_PI_2)) / 255.0;
00141 }
00142
00143
00144
00145 static const int switchIconInterval = 1000;
00146
00147 DelegateAnimationHandler::DelegateAnimationHandler(QObject *parent)
00148 : QObject(parent)
00149 {
00150 iconSequenceTimer.setSingleShot(true);
00151 iconSequenceTimer.setInterval(switchIconInterval);
00152 connect(&iconSequenceTimer, SIGNAL(timeout()), SLOT(sequenceTimerTimeout()));;
00153 }
00154
00155 DelegateAnimationHandler::~DelegateAnimationHandler()
00156 {
00157 timer.stop();
00158
00159 QMapIterator<const QAbstractItemView*, AnimationList*> i(animationLists);
00160 while (i.hasNext())
00161 {
00162 i.next();
00163 qDeleteAll(*i.value());
00164 delete i.value();
00165 }
00166 animationLists.clear();
00167 }
00168
00169 void DelegateAnimationHandler::sequenceTimerTimeout()
00170 {
00171 QAbstractItemModel* model = const_cast<QAbstractItemModel*>(sequenceModelIndex.model());
00172 QAbstractProxyModel* proxy = qobject_cast<QAbstractProxyModel*>(model);
00173 QModelIndex index = sequenceModelIndex;
00174
00175 if (proxy)
00176 {
00177 index = proxy->mapToSource(index);
00178 model = proxy->sourceModel();
00179 }
00180
00181 KDirModel* dirModel = dynamic_cast<KDirModel*>(model);
00182 if (dirModel)
00183 {
00184 kDebug(7000) << "requesting" << currentSequenceIndex;
00185 dirModel->requestSequenceIcon(index, currentSequenceIndex);
00186 iconSequenceTimer.start();
00187 }
00188 }
00189
00190 void DelegateAnimationHandler::gotNewIcon(const QModelIndex& index)
00191 {
00192 Q_UNUSED(index);
00193
00194 kDebug(7000) << currentSequenceIndex;
00195 if (sequenceModelIndex.isValid() && currentSequenceIndex)
00196 iconSequenceTimer.start();
00197
00198 ++currentSequenceIndex;
00199 }
00200
00201 void DelegateAnimationHandler::setSequenceIndex(int sequenceIndex)
00202 {
00203 kDebug(7000) << sequenceIndex;
00204
00205 if (sequenceIndex > 0)
00206 {
00207 currentSequenceIndex = sequenceIndex;
00208 iconSequenceTimer.start();
00209 }
00210 else
00211 {
00212 currentSequenceIndex = 0;
00213 sequenceTimerTimeout();
00214 currentSequenceIndex = 0;
00215 iconSequenceTimer.stop();
00216 }
00217 }
00218
00219 void DelegateAnimationHandler::eventuallyStartIteration(QModelIndex index)
00220 {
00221
00223
00224 if (sequenceModelIndex.isValid())
00225 setSequenceIndex(0);
00226
00227
00228 sequenceModelIndex = index;
00229 setSequenceIndex(1);
00230
00231 }
00232 AnimationState *DelegateAnimationHandler::animationState(const QStyleOption &option,
00233 const QModelIndex &index,
00234 const QAbstractItemView *view)
00235 {
00236
00237
00238
00239 if (!view || static_cast<const ProtectedAccessor*>(view)->draggingState())
00240 return NULL;
00241
00242 AnimationState *state = findAnimationState(view, index);
00243 bool hover = option.state & QStyle::State_MouseOver;
00244
00245
00246 if (!state && hover)
00247 {
00248 state = new AnimationState(index);
00249 addAnimationState(state, view);
00250
00251 if (!fadeInAddTime.isValid() ||
00252 (fadeInAddTime.isValid() && fadeInAddTime.elapsed() > 300))
00253 {
00254 startAnimation(state);
00255 }
00256 else
00257 {
00258 state->animating = false;
00259 state->progress = 1.0;
00260 state->direction = QTimeLine::Forward;
00261 }
00262
00263 fadeInAddTime.restart();
00264
00265 eventuallyStartIteration(index);
00266 }
00267 else if (state)
00268 {
00269
00270 if (!hover && (!state->animating || state->direction == QTimeLine::Forward))
00271 {
00272 state->direction = QTimeLine::Backward;
00273
00274 if (state->creationTime.elapsed() < 200)
00275 state->progress = 0.0;
00276
00277 startAnimation(state);
00278
00279
00280 if (index == sequenceModelIndex)
00281 {
00282 setSequenceIndex(0);
00283 sequenceModelIndex = QPersistentModelIndex();
00284 }
00285 }
00286 else if (hover && state->direction == QTimeLine::Backward)
00287 {
00288
00289
00290
00291
00292 state->direction = QTimeLine::Forward;
00293
00294 if (!state->animating)
00295 startAnimation(state);
00296
00297 eventuallyStartIteration(index);
00298 }
00299 }
00300 return state;
00301 }
00302
00303
00304 AnimationState *DelegateAnimationHandler::findAnimationState(const QAbstractItemView *view,
00305 const QModelIndex &index) const
00306 {
00307
00308 AnimationList *list = animationLists.value(view);
00309
00310 if (list)
00311 {
00312 foreach (AnimationState *state, *list)
00313 if (state->index == index)
00314 return state;
00315 }
00316
00317 return NULL;
00318 }
00319
00320
00321 void DelegateAnimationHandler::addAnimationState(AnimationState *state, const QAbstractItemView *view)
00322 {
00323 AnimationList *list = animationLists.value(view);
00324
00325
00326 if (!list)
00327 {
00328 connect(view, SIGNAL(destroyed(QObject*)), SLOT(viewDeleted(QObject*)));
00329
00330 list = new AnimationList;
00331 animationLists.insert(view, list);
00332 }
00333
00334 list->append(state);
00335 }
00336
00337 void DelegateAnimationHandler::restartAnimation(AnimationState *state)
00338 {
00339 startAnimation(state);
00340 }
00341
00342 void DelegateAnimationHandler::startAnimation(AnimationState *state)
00343 {
00344 state->time.start();
00345 state->animating = true;
00346
00347 if (!timer.isActive())
00348 timer.start(1000 / 30, this);
00349 }
00350
00351 int DelegateAnimationHandler::runAnimations(AnimationList *list, const QAbstractItemView *view)
00352 {
00353 int activeAnimations = 0;
00354 QRegion region;
00355
00356 QMutableLinkedListIterator<AnimationState*> i(*list);
00357 while (i.hasNext())
00358 {
00359 AnimationState *state = i.next();
00360
00361 if (!state->animating)
00362 continue;
00363
00364
00365
00366 if (state->index.isValid())
00367 {
00368 bool finished = state->update();
00369 region += view->visualRect(state->index);
00370
00371 if (!finished)
00372 {
00373 activeAnimations++;
00374 continue;
00375 }
00376 }
00377
00378
00379
00380
00381 if (state->direction == QTimeLine::Backward || !state->index.isValid())
00382 {
00383 delete state;
00384 i.remove();
00385 }
00386 }
00387
00388
00389 if (!region.isEmpty())
00390 const_cast<QAbstractItemView*>(view)->viewport()->update(region);
00391
00392 return activeAnimations;
00393 }
00394
00395
00396 void DelegateAnimationHandler::viewDeleted(QObject *view)
00397 {
00398 AnimationList *list = animationLists.take(static_cast<QAbstractItemView*>(view));
00399 qDeleteAll(*list);
00400 delete list;
00401 }
00402
00403
00404 void DelegateAnimationHandler::timerEvent(QTimerEvent *)
00405 {
00406 int activeAnimations = 0;
00407
00408 AnimationListsIterator i(animationLists);
00409 while (i.hasNext())
00410 {
00411 i.next();
00412 AnimationList *list = i.value();
00413 const QAbstractItemView *view = i.key();
00414
00415 activeAnimations += runAnimations(list, view);
00416 }
00417
00418 if (activeAnimations == 0 && timer.isActive())
00419 timer.stop();
00420 }
00421
00422 }
00423