Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / util / qdeclarativebehavior.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 QtDeclarative 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 #include "private/qdeclarativebehavior_p.h"
43
44 #include "private/qdeclarativeanimation_p.h"
45 #include "private/qdeclarativetransition_p.h"
46
47 #include <qdeclarativecontext.h>
48 #include <qdeclarativeinfo.h>
49 #include <qdeclarativeproperty_p.h>
50 #include <qdeclarativeguard_p.h>
51 #include <qdeclarativeengine_p.h>
52
53 #include <private/qobject_p.h>
54
55 QT_BEGIN_NAMESPACE
56
57 class QDeclarativeBehaviorPrivate : public QObjectPrivate
58 {
59     Q_DECLARE_PUBLIC(QDeclarativeBehavior)
60 public:
61     QDeclarativeBehaviorPrivate() : animation(0), enabled(true), finalized(false)
62       , blockRunningChanged(false) {}
63
64     QDeclarativeProperty property;
65     QVariant currentValue;
66     QVariant targetValue;
67     QDeclarativeGuard<QDeclarativeAbstractAnimation> animation;
68     bool enabled;
69     bool finalized;
70     bool blockRunningChanged;
71 };
72
73 /*!
74     \qmlclass Behavior QDeclarativeBehavior
75     \ingroup qml-animation-transition
76     \since 4.7
77     \brief The Behavior element allows you to specify a default animation for a property change.
78
79     A Behavior defines the default animation to be applied whenever a
80     particular property value changes.
81
82     For example, the following Behavior defines a NumberAnimation to be run
83     whenever the \l Rectangle's \c width value changes. When the MouseArea
84     is clicked, the \c width is changed, triggering the behavior's animation:
85
86     \snippet doc/src/snippets/declarative/behavior.qml 0
87
88     Note that a property cannot have more than one assigned Behavior. To provide
89     multiple animations within a Behavior, use ParallelAnimation or
90     SequentialAnimation.
91
92     If a \l{QML States}{state change} has a \l Transition that matches the same property as a
93     Behavior, the \l Transition animation overrides the Behavior for that
94     state change. For general advice on using Behaviors to animate state changes, see
95     \l{Using QML Behaviors with States}.
96
97     \sa {QML Animation and Transitions}, {declarative/animation/behaviors}{Behavior example}, QtDeclarative
98 */
99
100
101 QDeclarativeBehavior::QDeclarativeBehavior(QObject *parent)
102     : QObject(*(new QDeclarativeBehaviorPrivate), parent)
103 {
104 }
105
106 QDeclarativeBehavior::~QDeclarativeBehavior()
107 {
108 }
109
110 /*!
111     \qmlproperty Animation Behavior::animation
112     \default
113
114     This property holds the animation to run when the behavior is triggered.
115 */
116
117 QDeclarativeAbstractAnimation *QDeclarativeBehavior::animation()
118 {
119     Q_D(QDeclarativeBehavior);
120     return d->animation;
121 }
122
123 void QDeclarativeBehavior::setAnimation(QDeclarativeAbstractAnimation *animation)
124 {
125     Q_D(QDeclarativeBehavior);
126     if (d->animation) {
127         qmlInfo(this) << tr("Cannot change the animation assigned to a Behavior.");
128         return;
129     }
130
131     d->animation = animation;
132     if (d->animation) {
133         d->animation->setDefaultTarget(d->property);
134         d->animation->setDisableUserControl();
135         connect(d->animation->qtAnimation(),
136                 SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)),
137                 this,
138                 SLOT(qtAnimationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State)));
139     }
140 }
141
142
143 void QDeclarativeBehavior::qtAnimationStateChanged(QAbstractAnimation::State newState,QAbstractAnimation::State)
144 {
145     Q_D(QDeclarativeBehavior);
146     if (!d->blockRunningChanged)
147         d->animation->notifyRunningChanged(newState == QAbstractAnimation::Running);
148 }
149
150
151 /*!
152     \qmlproperty bool 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 QDeclarativeBehavior::enabled() const
161 {
162     Q_D(const QDeclarativeBehavior);
163     return d->enabled;
164 }
165
166 void QDeclarativeBehavior::setEnabled(bool enabled)
167 {
168     Q_D(QDeclarativeBehavior);
169     if (d->enabled == enabled)
170         return;
171     d->enabled = enabled;
172     emit enabledChanged();
173 }
174
175 void QDeclarativeBehavior::write(const QVariant &value)
176 {
177     Q_D(QDeclarativeBehavior);
178     qmlExecuteDeferred(this);
179     if (!d->animation || !d->enabled || !d->finalized) {
180         QDeclarativePropertyPrivate::write(d->property, value, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
181         d->targetValue = value;
182         return;
183     }
184
185     if (d->animation->isRunning() && value == d->targetValue)
186         return;
187
188     d->currentValue = d->property.read();
189     d->targetValue = value;
190
191     if (d->animation->qtAnimation()->duration() != -1
192             && d->animation->qtAnimation()->state() != QAbstractAnimation::Stopped) {
193         d->blockRunningChanged = true;
194         d->animation->qtAnimation()->stop();
195     }
196
197     QDeclarativeStateOperation::ActionList actions;
198     QDeclarativeAction action;
199     action.property = d->property;
200     action.fromValue = d->currentValue;
201     action.toValue = value;
202     actions << action;
203
204     QList<QDeclarativeProperty> after;
205     d->animation->transition(actions, after, QDeclarativeAbstractAnimation::Forward);
206     d->animation->qtAnimation()->start();
207     d->blockRunningChanged = false;
208     if (!after.contains(d->property))
209         QDeclarativePropertyPrivate::write(d->property, value, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
210 }
211
212 void QDeclarativeBehavior::setTarget(const QDeclarativeProperty &property)
213 {
214     Q_D(QDeclarativeBehavior);
215     d->property = property;
216     d->currentValue = property.read();
217     if (d->animation)
218         d->animation->setDefaultTarget(property);
219
220     QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
221     engPriv->registerFinalizedParserStatusObject(this, this->metaObject()->indexOfSlot("componentFinalized()"));
222 }
223
224 void QDeclarativeBehavior::componentFinalized()
225 {
226     Q_D(QDeclarativeBehavior);
227     d->finalized = true;
228 }
229
230 QT_END_NAMESPACE