b490a41a8350306e66885d1afc65709a7059344b
[profile/ivi/qtdeclarative.git] / src / quick / util / qdeclarativebind.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativebind_p.h"
43
44 #include <private/qdeclarativenullablevalue_p_p.h>
45 #include <private/qdeclarativeproperty_p.h>
46 #include <private/qdeclarativebinding_p.h>
47 #include <private/qdeclarativeguard_p.h>
48
49 #include <qdeclarativeengine.h>
50 #include <qdeclarativecontext.h>
51 #include <qdeclarativeproperty.h>
52 #include <qdeclarativeinfo.h>
53
54 #include <QtCore/qfile.h>
55 #include <QtCore/qdebug.h>
56
57 #include <private/qobject_p.h>
58
59 QT_BEGIN_NAMESPACE
60
61 class QDeclarativeBindPrivate : public QObjectPrivate
62 {
63 public:
64     QDeclarativeBindPrivate() : componentComplete(true), obj(0), prevBind(0) {}
65     ~QDeclarativeBindPrivate() { if (prevBind) prevBind->destroy(); }
66
67     QDeclarativeNullableValue<bool> when;
68     bool componentComplete;
69     QDeclarativeGuard<QObject> obj;
70     QString propName;
71     QDeclarativeNullableValue<QVariant> value;
72     QDeclarativeProperty prop;
73     QDeclarativeAbstractBinding *prevBind;
74 };
75
76
77 /*!
78     \qmlclass Binding QDeclarativeBind
79     \inqmlmodule QtQuick 2
80     \ingroup qml-working-with-data
81     \brief The Binding element allows arbitrary property bindings to be created.
82
83     \section1 Binding to an inaccessible property
84
85     Sometimes it is necessary to bind to a property of an object that wasn't
86     directly instantiated by QML - generally a property of a class exported
87     to QML by C++. In these cases, regular property binding doesn't work. Binding
88     allows you to bind any value to any property.
89
90     For example, imagine a C++ application that maps an "app.enteredText"
91     property into QML. You could use Binding to update the enteredText property
92     like this.
93     \code
94     TextEdit { id: myTextField; text: "Please type here..." }
95     Binding { target: app; property: "enteredText"; value: myTextField.text }
96     \endcode
97     Whenever the text in the TextEdit is updated, the C++ property will be
98     updated also.
99
100     \section1 "Single-branch" conditional binding
101
102     In some circumstances you may want to control the value of a property
103     only when a certain condition is true (and relinquish control in all
104     other cirumstances). This often isn't possible to accomplish with a direct
105     binding, as you need to supply values for all possible branches.
106
107     \qml
108     // warning: "Unable to assign [undefined] to double value"
109     value: if (mouse.pressed) mouse.mouseX
110     \endqml
111
112     The above example will produce a warning whenever we release the mouse, as the value
113     of the binding is undefined when the mouse isn't pressed. We can use the Binding
114     element to rewrite the above code and avoid the warning.
115
116     \qml
117     Binding on value {
118         when: mouse.pressed
119         value: mouse.mouseX
120     }
121     \endqml
122
123     The Binding element will also restore any previously set direct bindings on
124     the property. In that sense, it functions much like a simplified State.
125
126     \qml
127     // this is equivilant to the above Binding
128     State {
129         name: "pressed"
130         when: mouse.pressed
131         PropertyChanges {
132             target: obj
133             value: mouse.mouseX
134         }
135     }
136     \endqml
137
138     If the binding target or binding property is changed, the bound value is
139     immediately pushed onto the new target.
140
141     \sa QtDeclarative
142 */
143 QDeclarativeBind::QDeclarativeBind(QObject *parent)
144     : QObject(*(new QDeclarativeBindPrivate), parent)
145 {
146 }
147
148 QDeclarativeBind::~QDeclarativeBind()
149 {
150 }
151
152 /*!
153     \qmlproperty bool QtQuick2::Binding::when
154
155     This property holds when the binding is active.
156     This should be set to an expression that evaluates to true when you want the binding to be active.
157
158     \code
159     Binding {
160         target: contactName; property: 'text'
161         value: name; when: list.ListView.isCurrentItem
162     }
163     \endcode
164
165     When the binding becomes inactive again, any direct bindings that were previously
166     set on the property will be restored.
167 */
168 bool QDeclarativeBind::when() const
169 {
170     Q_D(const QDeclarativeBind);
171     return d->when;
172 }
173
174 void QDeclarativeBind::setWhen(bool v)
175 {
176     Q_D(QDeclarativeBind);
177     if (!d->when.isNull && d->when == v)
178         return;
179
180     d->when = v;
181     eval();
182 }
183
184 /*!
185     \qmlproperty Object QtQuick2::Binding::target
186
187     The object to be updated.
188 */
189 QObject *QDeclarativeBind::object()
190 {
191     Q_D(const QDeclarativeBind);
192     return d->obj;
193 }
194
195 void QDeclarativeBind::setObject(QObject *obj)
196 {
197     Q_D(QDeclarativeBind);
198     if (d->obj && d->when.isValid() && d->when) {
199         /* if we switch the object at runtime, we need to restore the
200            previous binding on the old object before continuing */
201         d->when = false;
202         eval();
203         d->when = true;
204     }
205     d->obj = obj;
206     if (d->componentComplete)
207         d->prop = QDeclarativeProperty(d->obj, d->propName);
208     eval();
209 }
210
211 /*!
212     \qmlproperty string QtQuick2::Binding::property
213
214     The property to be updated.
215 */
216 QString QDeclarativeBind::property() const
217 {
218     Q_D(const QDeclarativeBind);
219     return d->propName;
220 }
221
222 void QDeclarativeBind::setProperty(const QString &p)
223 {
224     Q_D(QDeclarativeBind);
225     if (!d->propName.isEmpty() && d->when.isValid() && d->when) {
226         /* if we switch the property name at runtime, we need to restore the
227            previous binding on the old object before continuing */
228         d->when = false;
229         eval();
230         d->when = true;
231     }
232     d->propName = p;
233     if (d->componentComplete)
234         d->prop = QDeclarativeProperty(d->obj, d->propName);
235     eval();
236 }
237
238 /*!
239     \qmlproperty any QtQuick2::Binding::value
240
241     The value to be set on the target object and property.  This can be a
242     constant (which isn't very useful), or a bound expression.
243 */
244 QVariant QDeclarativeBind::value() const
245 {
246     Q_D(const QDeclarativeBind);
247     return d->value.value;
248 }
249
250 void QDeclarativeBind::setValue(const QVariant &v)
251 {
252     Q_D(QDeclarativeBind);
253     d->value = v;
254     eval();
255 }
256
257 void QDeclarativeBind::setTarget(const QDeclarativeProperty &p)
258 {
259     Q_D(QDeclarativeBind);
260     d->prop = p;
261 }
262
263 void QDeclarativeBind::classBegin()
264 {
265     Q_D(QDeclarativeBind);
266     d->componentComplete = false;
267 }
268
269 void QDeclarativeBind::componentComplete()
270 {
271     Q_D(QDeclarativeBind);
272     d->componentComplete = true;
273     if (!d->prop.isValid())
274         d->prop = QDeclarativeProperty(d->obj, d->propName);
275     eval();
276 }
277
278 void QDeclarativeBind::eval()
279 {
280     Q_D(QDeclarativeBind);
281     if (!d->prop.isValid() || d->value.isNull || !d->componentComplete)
282         return;
283
284     if (d->when.isValid()) {
285         if (!d->when) {
286             //restore any previous binding
287             if (d->prevBind) {
288                 QDeclarativeAbstractBinding *tmp = d->prevBind;
289                 d->prevBind = 0;
290                 tmp = QDeclarativePropertyPrivate::setBinding(d->prop, tmp);
291                 if (tmp) //should this ever be true?
292                     tmp->destroy();
293             }
294             return;
295         }
296
297         //save any set binding for restoration
298         QDeclarativeAbstractBinding *tmp;
299         tmp = QDeclarativePropertyPrivate::setBinding(d->prop, 0);
300         if (tmp && d->prevBind)
301             d->prevBind->destroy();
302         else if (!d->prevBind)
303             d->prevBind = tmp;
304     }
305
306     d->prop.write(d->value.value);
307 }
308
309 QT_END_NAMESPACE