src/corelib/animation/qpropertyanimation.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtCore module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*!
       
    43     \class QPropertyAnimation
       
    44     \brief The QPropertyAnimation class animates Qt properties
       
    45     \since 4.6
       
    46 
       
    47     \ingroup animation
       
    48 
       
    49     QPropertyAnimation interpolates over \l{Qt's Property System}{Qt
       
    50     properties}. As property values are stored in \l{QVariant}s, the
       
    51     class inherits QVariantAnimation, and supports animation of the
       
    52     same \l{QVariant::Type}{variant types} as its super class.
       
    53 
       
    54     A class declaring properties must be a QObject. To make it
       
    55     possible to animate a property, it must provide a setter (so that
       
    56     QPropertyAnimation can set the property's value). Note that this
       
    57     makes it possible to animate many of Qt's widgets. Let's look at
       
    58     an example:
       
    59 
       
    60     \code
       
    61         QPropertyAnimation animation(myWidget, "geometry");
       
    62         animation.setDuration(10000);
       
    63         animation.setStartValue(QRect(0, 0, 100, 30));
       
    64         animation.setEndValue(QRect(250, 250, 100, 30));
       
    65 
       
    66         animation.start();
       
    67     \endcode
       
    68 
       
    69     The property name and the QObject instance of which property
       
    70     should be animated are passed to the constructor. You can then
       
    71     specify the start and end value of the property. The procedure is
       
    72     equal for properties in classes you have implemented
       
    73     yourself--just check with QVariantAnimation that your QVariant
       
    74     type is supported.
       
    75 
       
    76     The QVariantAnimation class description explains how to set up the
       
    77     animation in detail. Note, however, that if a start value is not
       
    78     set, the property will start at the value it had when the
       
    79     QPropertyAnimation instance was created.
       
    80 
       
    81     QPropertyAnimation works like a charm on its own. For complex
       
    82     animations that, for instance, contain several objects,
       
    83     QAnimationGroup is provided. An animation group is an animation
       
    84     that can contain other animations, and that can manage when its
       
    85     animations are played. Look at QParallelAnimationGroup for an
       
    86     example.
       
    87 
       
    88     \sa QVariantAnimation, QAnimationGroup, {The Animation Framework}
       
    89 */
       
    90 
       
    91 #include "qpropertyanimation.h"
       
    92 #include "qanimationgroup.h"
       
    93 #include "qpropertyanimation_p.h"
       
    94 
       
    95 #include <private/qmutexpool_p.h>
       
    96 
       
    97 #ifndef QT_NO_ANIMATION
       
    98 
       
    99 QT_BEGIN_NAMESPACE
       
   100 
       
   101 void QPropertyAnimationPrivate::updateMetaProperty()
       
   102 {
       
   103     if (!target || propertyName.isEmpty()) {
       
   104         propertyType = QVariant::Invalid;
       
   105         propertyIndex = -1;
       
   106         return;
       
   107     }
       
   108 
       
   109     //propertyType will be set to a valid type only if there is a Q_PROPERTY
       
   110     //otherwise it will be set to QVariant::Invalid at the end of this function
       
   111     propertyType = targetValue->property(propertyName).userType();
       
   112     propertyIndex = targetValue->metaObject()->indexOfProperty(propertyName);
       
   113 
       
   114     if (propertyType != QVariant::Invalid)
       
   115         convertValues(propertyType);
       
   116     if (propertyIndex == -1) {
       
   117         //there is no Q_PROPERTY on the object
       
   118         propertyType = QVariant::Invalid;
       
   119         if (!targetValue->dynamicPropertyNames().contains(propertyName))
       
   120             qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName.constData());
       
   121     }
       
   122 }
       
   123 
       
   124 void QPropertyAnimationPrivate::updateProperty(const QVariant &newValue)
       
   125 {
       
   126     if (state == QAbstractAnimation::Stopped)
       
   127         return;
       
   128 
       
   129     if (!target) {
       
   130         q_func()->stop(); //the target was destroyed we need to stop the animation
       
   131         return;
       
   132     }
       
   133 
       
   134     if (newValue.userType() == propertyType) {
       
   135         //no conversion is needed, we directly call the QMetaObject::metacall
       
   136         void *data = const_cast<void*>(newValue.constData());
       
   137         QMetaObject::metacall(targetValue, QMetaObject::WriteProperty, propertyIndex, &data);
       
   138     } else {
       
   139         targetValue->setProperty(propertyName.constData(), newValue);
       
   140     }
       
   141 }
       
   142 
       
   143 /*!
       
   144     Construct a QPropertyAnimation object. \a parent is passed to QObject's
       
   145     constructor.
       
   146 */
       
   147 QPropertyAnimation::QPropertyAnimation(QObject *parent)
       
   148     : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
       
   149 {
       
   150 }
       
   151 
       
   152 /*!
       
   153     Construct a QPropertyAnimation object. \a parent is passed to QObject's
       
   154     constructor. The animation changes the property \a propertyName on \a
       
   155     target. The default duration is 250ms.
       
   156 
       
   157     \sa targetObject, propertyName
       
   158 */
       
   159 QPropertyAnimation::QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent)
       
   160     : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
       
   161 {
       
   162     setTargetObject(target);
       
   163     setPropertyName(propertyName);
       
   164 }
       
   165 
       
   166 /*!
       
   167     Destroys the QPropertyAnimation instance.
       
   168  */
       
   169 QPropertyAnimation::~QPropertyAnimation()
       
   170 {
       
   171     stop();
       
   172 }
       
   173 
       
   174 /*!
       
   175     \property QPropertyAnimation::targetObject
       
   176     \brief the target QObject for this animation.
       
   177 
       
   178     This property defines the target QObject for this animation.
       
   179  */
       
   180 QObject *QPropertyAnimation::targetObject() const
       
   181 {
       
   182     return d_func()->target.data();
       
   183 }
       
   184 
       
   185 void QPropertyAnimation::setTargetObject(QObject *target)
       
   186 {
       
   187     Q_D(QPropertyAnimation);
       
   188     if (d->targetValue == target)
       
   189         return;
       
   190 
       
   191     if (d->state != QAbstractAnimation::Stopped) {
       
   192         qWarning("QPropertyAnimation::setTargetObject: you can't change the target of a running animation");
       
   193         return;
       
   194     }
       
   195 
       
   196     d->target = d->targetValue = target;
       
   197     d->updateMetaProperty();
       
   198 }
       
   199 
       
   200 /*!
       
   201     \property QPropertyAnimation::propertyName
       
   202     \brief the target property name for this animation
       
   203 
       
   204     This property defines the target property name for this animation. The
       
   205     property name is required for the animation to operate.
       
   206  */
       
   207 QByteArray QPropertyAnimation::propertyName() const
       
   208 {
       
   209     Q_D(const QPropertyAnimation);
       
   210     return d->propertyName;
       
   211 }
       
   212 
       
   213 void QPropertyAnimation::setPropertyName(const QByteArray &propertyName)
       
   214 {
       
   215     Q_D(QPropertyAnimation);
       
   216     if (d->state != QAbstractAnimation::Stopped) {
       
   217         qWarning("QPropertyAnimation::setPropertyName: you can't change the property name of a running animation");
       
   218         return;
       
   219     }
       
   220 
       
   221     d->propertyName = propertyName;
       
   222     d->updateMetaProperty();
       
   223 }
       
   224 
       
   225 
       
   226 /*!
       
   227     \reimp
       
   228  */
       
   229 bool QPropertyAnimation::event(QEvent *event)
       
   230 {
       
   231     return QVariantAnimation::event(event);
       
   232 }
       
   233 
       
   234 /*!
       
   235     This virtual function is called by QVariantAnimation whenever the current value
       
   236     changes. \a value is the new, updated value. It updates the current value
       
   237     of the property on the target object.
       
   238 
       
   239     \sa currentValue, currentTime
       
   240  */
       
   241 void QPropertyAnimation::updateCurrentValue(const QVariant &value)
       
   242 {
       
   243     Q_D(QPropertyAnimation);
       
   244     d->updateProperty(value);
       
   245 }
       
   246 
       
   247 /*!
       
   248     \reimp
       
   249 
       
   250     If the startValue is not defined when the state of the animation changes from Stopped to Running,
       
   251     the current property value is used as the initial value for the animation.
       
   252 */
       
   253 void QPropertyAnimation::updateState(QAbstractAnimation::State oldState,
       
   254                                      QAbstractAnimation::State newState)
       
   255 {
       
   256     Q_D(QPropertyAnimation);
       
   257 
       
   258     if (!d->target && oldState == Stopped) {
       
   259         qWarning("QPropertyAnimation::updateState: Changing state of an animation without target");
       
   260         return;
       
   261     }
       
   262 
       
   263     QVariantAnimation::updateState(oldState, newState);
       
   264 
       
   265     QPropertyAnimation *animToStop = 0;
       
   266     {
       
   267         QMutexLocker locker(QMutexPool::globalInstanceGet(&staticMetaObject));
       
   268         typedef QPair<QObject *, QByteArray> QPropertyAnimationPair;
       
   269         typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash;
       
   270         static QPropertyAnimationHash hash;
       
   271         //here we need to use value because we need to know to which pointer
       
   272         //the animation was referring in case stopped because the target was destroyed
       
   273         QPropertyAnimationPair key(d->targetValue, d->propertyName);
       
   274         if (newState == Running) {
       
   275             d->updateMetaProperty();
       
   276             animToStop = hash.value(key, 0);
       
   277             hash.insert(key, this);
       
   278             // update the default start value
       
   279             if (oldState == Stopped) {
       
   280                 d->setDefaultStartEndValue(d->targetValue->property(d->propertyName.constData()));
       
   281                 //let's check if we have a start value and an end value
       
   282                 if (!startValue().isValid() && (d->direction == Backward || !d->defaultStartEndValue.isValid()))
       
   283                     qWarning("QPropertyAnimation::updateState: starting an animation without start value");
       
   284                 if (!endValue().isValid() && (d->direction == Forward || !d->defaultStartEndValue.isValid()))
       
   285                     qWarning("QPropertyAnimation::updateState: starting an animation without end value");
       
   286             }
       
   287         } else if (hash.value(key) == this) {
       
   288             hash.remove(key);
       
   289         }
       
   290     }
       
   291 
       
   292     //we need to do that after the mutex was unlocked
       
   293     if (animToStop) {
       
   294         // try to stop the top level group
       
   295         QAbstractAnimation *current = animToStop;
       
   296         while (current->group() && current->state() != Stopped)
       
   297             current = current->group();
       
   298         current->stop();
       
   299     }
       
   300 }
       
   301 
       
   302 #include "moc_qpropertyanimation.cpp"
       
   303 
       
   304 QT_END_NAMESPACE
       
   305 
       
   306 #endif //QT_NO_ANIMATION