a58dbba28fca5223068a6bd0c4bc010b9f7b993d
[profile/ivi/qtdeclarative.git] / src / quick / util / qquickbehavior.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickbehavior_p.h"
43
44 #include "qquickanimation_p.h"
45 #include <qqmlcontext.h>
46 #include <qqmlinfo.h>
47 #include <private/qqmlproperty_p.h>
48 #include <private/qqmlguard_p.h>
49 #include <private/qqmlengine_p.h>
50 #include <private/qabstractanimationjob_p.h>
51 #include <private/qquicktransition_p.h>
52
53 #include <private/qobject_p.h>
54
55 QT_BEGIN_NAMESPACE
56
57 class QQuickBehaviorPrivate : public QObjectPrivate, public QAnimationJobChangeListener
58 {
59     Q_DECLARE_PUBLIC(QQuickBehavior)
60 public:
61     QQuickBehaviorPrivate() : animation(0), animationInstance(0), enabled(true), finalized(false)
62       , blockRunningChanged(false) {}
63
64     virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
65
66     QQmlProperty property;
67     QVariant targetValue;
68     QQmlGuard<QQuickAbstractAnimation> animation;
69     QAbstractAnimationJob *animationInstance;
70     bool enabled;
71     bool finalized;
72     bool blockRunningChanged;
73 };
74
75 /*!
76     \qmltype Behavior
77     \instantiates QQuickBehavior
78     \inqmlmodule QtQuick 2
79     \ingroup qtquick-transitions-animations
80     \ingroup qtquick-interceptors
81     \brief Defines a default animation for a property change
82
83     A Behavior defines the default animation to be applied whenever a
84     particular property value changes.
85
86     For example, the following Behavior defines a NumberAnimation to be run
87     whenever the \l Rectangle's \c width value changes. When the MouseArea
88     is clicked, the \c width is changed, triggering the behavior's animation:
89
90     \snippet qml/behavior.qml 0
91
92     Note that a property cannot have more than one assigned Behavior. To provide
93     multiple animations within a Behavior, use ParallelAnimation or
94     SequentialAnimation.
95
96     If a \l{Qt Quick States}{state change} has a \l Transition that matches the same property as a
97     Behavior, the \l Transition animation overrides the Behavior for that
98     state change. For general advice on using Behaviors to animate state changes, see
99     \l{Using Qt Quick Behaviors with States}.
100
101     \sa {Animation and Transitions in Qt Quick}, {declarative/animation/behaviors}{Behavior example}, QtQml
102 */
103
104
105 QQuickBehavior::QQuickBehavior(QObject *parent)
106     : QObject(*(new QQuickBehaviorPrivate), parent)
107 {
108 }
109
110 QQuickBehavior::~QQuickBehavior()
111 {
112     Q_D(QQuickBehavior);
113     delete d->animationInstance;
114 }
115
116 /*!
117     \qmlproperty Animation QtQuick2::Behavior::animation
118     \default
119
120     This property holds the animation to run when the behavior is triggered.
121 */
122
123 QQuickAbstractAnimation *QQuickBehavior::animation()
124 {
125     Q_D(QQuickBehavior);
126     return d->animation;
127 }
128
129 void QQuickBehavior::setAnimation(QQuickAbstractAnimation *animation)
130 {
131     Q_D(QQuickBehavior);
132     if (d->animation) {
133         qmlInfo(this) << tr("Cannot change the animation assigned to a Behavior.");
134         return;
135     }
136
137     d->animation = animation;
138     if (d->animation) {
139         d->animation->setDefaultTarget(d->property);
140         d->animation->setDisableUserControl();
141     }
142 }
143
144
145 void QQuickBehaviorPrivate::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState,QAbstractAnimationJob::State)
146 {
147     if (!blockRunningChanged)
148         animation->notifyRunningChanged(newState == QAbstractAnimationJob::Running);
149 }
150
151 /*!
152     \qmlproperty bool QtQuick2::Behavior::enabled
153
154     This property holds whether the behavior will be triggered when the tracked
155     property changes value.
156
157     By default a Behavior is enabled.
158 */
159
160 bool QQuickBehavior::enabled() const
161 {
162     Q_D(const QQuickBehavior);
163     return d->enabled;
164 }
165
166 void QQuickBehavior::setEnabled(bool enabled)
167 {
168     Q_D(QQuickBehavior);
169     if (d->enabled == enabled)
170         return;
171     d->enabled = enabled;
172     emit enabledChanged();
173 }
174
175 void QQuickBehavior::write(const QVariant &value)
176 {
177     Q_D(QQuickBehavior);
178     bool bypass = !d->enabled || !d->finalized;
179     if (!bypass)
180         qmlExecuteDeferred(this);
181     if (!d->animation || bypass) {
182         QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
183         d->targetValue = value;
184         return;
185     }
186
187     if (d->animation->isRunning() && value == d->targetValue)
188         return;
189
190     const QVariant &currentValue = d->property.read();
191     d->targetValue = value;
192
193     if (d->animationInstance && d->animationInstance->duration() != -1
194             && !d->animationInstance->isStopped()) {
195         d->blockRunningChanged = true;
196         d->animationInstance->stop();
197     }
198
199     QQuickStateOperation::ActionList actions;
200     QQuickAction action;
201     action.property = d->property;
202     action.fromValue = currentValue;
203     action.toValue = value;
204     actions << action;
205
206     QList<QQmlProperty> after;
207     QAbstractAnimationJob *prev = d->animationInstance;
208     d->animationInstance = d->animation->transition(actions, after, QQuickAbstractAnimation::Forward);
209     if (prev && prev != d->animationInstance)
210         delete prev;
211
212     if (d->animationInstance) {
213         if (d->animationInstance != prev)
214             d->animationInstance->addAnimationChangeListener(d, QAbstractAnimationJob::StateChange);
215         d->animationInstance->start();
216         d->blockRunningChanged = false;
217     }
218     if (!after.contains(d->property))
219         QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
220 }
221
222 void QQuickBehavior::setTarget(const QQmlProperty &property)
223 {
224     Q_D(QQuickBehavior);
225     d->property = property;
226     if (d->animation)
227         d->animation->setDefaultTarget(property);
228
229     QQmlEnginePrivate *engPriv = QQmlEnginePrivate::get(qmlEngine(this));
230     static int finalizedIdx = -1;
231     if (finalizedIdx < 0)
232         finalizedIdx = metaObject()->indexOfSlot("componentFinalized()");
233     engPriv->registerFinalizeCallback(this, finalizedIdx);
234 }
235
236 void QQuickBehavior::componentFinalized()
237 {
238     Q_D(QQuickBehavior);
239     d->finalized = true;
240 }
241
242 QT_END_NAMESPACE