4c29fcef835ded6691ea5a16248ef88b649b4de8
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativebinding.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 QtDeclarative 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 "qdeclarativebinding_p.h"
43 #include "qdeclarativebinding_p_p.h"
44
45 #include "qdeclarative.h"
46 #include "qdeclarativecontext.h"
47 #include "qdeclarativeinfo.h"
48 #include "qdeclarativecompiler_p.h"
49 #include "qdeclarativedata_p.h"
50 #include <private/qdeclarativedebugtrace_p.h>
51 #include <private/qdeclarativetrace_p.h>
52
53 #include <QVariant>
54 #include <QtCore/qdebug.h>
55
56 QT_BEGIN_NAMESPACE
57
58 QDeclarativeAbstractBinding::QDeclarativeAbstractBinding()
59 : m_object(0), m_propertyIndex(-1), m_mePtr(0), m_prevBinding(0), m_nextBinding(0)
60 {
61 }
62
63 QDeclarativeAbstractBinding::~QDeclarativeAbstractBinding()
64 {
65     Q_ASSERT(m_prevBinding == 0);
66     Q_ASSERT(m_mePtr == 0);
67 }
68
69 /*!
70 Destroy the binding.  Use this instead of calling delete.
71
72 Bindings are free to implement their own memory management, so the delete operator is not 
73 necessarily safe.  The default implementation clears the binding, removes it from the object
74 and calls delete.
75 */
76 void QDeclarativeAbstractBinding::destroy()
77 {
78     removeFromObject();
79     clear();
80
81     delete this;
82 }
83
84 /*!
85 Add this binding to \a object.
86
87 This transfers ownership of the binding to the object, marks the object's property as
88 being bound.  
89
90 However, it does not enable the binding itself or call update() on it.
91 */
92 void QDeclarativeAbstractBinding::addToObject(QObject *object, int index)
93 {
94     Q_ASSERT(object);
95
96     if (m_object == object && m_propertyIndex == index)
97         return;
98
99     removeFromObject();
100
101     Q_ASSERT(!m_prevBinding);
102
103     m_object = object;
104     m_propertyIndex = index;
105
106     QDeclarativeData *data = QDeclarativeData::get(object, true);
107
108     if (index & 0xFF000000) {
109         // Value type
110
111         int coreIndex = index & 0xFFFFFF;
112
113         // Find the value type proxy (if there is one)
114         QDeclarativeValueTypeProxyBinding *proxy = 0;
115         if (data->hasBindingBit(coreIndex)) {
116             QDeclarativeAbstractBinding *b = data->bindings;
117             while (b && b->propertyIndex() != coreIndex)
118                 b = b->m_nextBinding;
119             Q_ASSERT(b && b->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy);
120             proxy = static_cast<QDeclarativeValueTypeProxyBinding *>(b);
121         }
122
123         if (!proxy) {
124             proxy = new QDeclarativeValueTypeProxyBinding(object, coreIndex);
125             proxy->addToObject(object, coreIndex);
126         }
127
128         m_nextBinding = proxy->m_bindings;
129         if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
130         m_prevBinding = &proxy->m_bindings;
131         proxy->m_bindings = this;
132
133     } else {
134         m_nextBinding = data->bindings;
135         if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
136         m_prevBinding = &data->bindings;
137         data->bindings = this;
138
139         data->setBindingBit(m_object, index);
140     }
141 }
142
143 /*!
144 Remove the binding from the object.
145 */
146 void QDeclarativeAbstractBinding::removeFromObject()
147 {
148     if (m_prevBinding) {
149         int index = propertyIndex();
150
151         *m_prevBinding = m_nextBinding;
152         if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding;
153         m_prevBinding = 0;
154         m_nextBinding = 0;
155
156         if (index & 0xFF000000) {
157             // Value type - we don't remove the proxy from the object.  It will sit their happily
158             // doing nothing until it is removed by a write, a binding change or it is reused
159             // to hold more sub-bindings.
160         } else if (m_object) {
161             QDeclarativeData *data = QDeclarativeData::get(m_object, false);
162             if (data) data->clearBindingBit(index);
163         }
164
165         m_object = 0;
166         m_propertyIndex = -1;
167     }
168 }
169
170 static void bindingDummyDeleter(QDeclarativeAbstractBinding *)
171 {
172 }
173
174 QDeclarativeAbstractBinding::Pointer QDeclarativeAbstractBinding::weakPointer()
175 {
176     if (m_selfPointer.isNull())
177         m_selfPointer = QSharedPointer<QDeclarativeAbstractBinding>(this, bindingDummyDeleter);
178
179     return m_selfPointer.toWeakRef();
180 }
181
182 void QDeclarativeAbstractBinding::clear()
183 {
184     if (m_mePtr) {
185         *m_mePtr = 0;
186         m_mePtr = 0;
187     }
188 }
189
190 QString QDeclarativeAbstractBinding::expression() const
191 {
192     return QLatin1String("<Unknown>");
193 }
194
195 QObject *QDeclarativeAbstractBinding::object() const
196 {
197     return m_object;
198 }
199
200 int QDeclarativeAbstractBinding::propertyIndex() const
201 {
202     return m_propertyIndex;
203 }
204
205 void QDeclarativeAbstractBinding::setEnabled(bool enabled, QDeclarativePropertyPrivate::WriteFlags flags)
206 {
207     if (enabled) update(flags);
208 }
209
210 QDeclarativeBinding::Identifier QDeclarativeBinding::Invalid = -1;
211
212 void QDeclarativeBindingPrivate::refresh()
213 {
214     Q_Q(QDeclarativeBinding);
215     q->update();
216 }
217
218 QDeclarativeBindingPrivate::QDeclarativeBindingPrivate()
219 : updating(false), enabled(false)
220 {
221 }
222
223 QDeclarativeBindingPrivate::~QDeclarativeBindingPrivate()
224 {
225 }
226
227 QDeclarativeBinding *
228 QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeContext *ctxt,
229                                    const QString &url, int lineNumber, QObject *parent)
230 {
231     if (id < 0)
232         return 0;
233
234     QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(ctxt);
235
236     QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(ctxt->engine());
237     QDeclarativeCompiledData *cdata = 0;
238     QDeclarativeTypeData *typeData = 0;
239     if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
240         typeData = engine->typeLoader.get(ctxtdata->url);
241         cdata = typeData->compiledData();
242     }
243     QDeclarativeBinding *rv = cdata ? new QDeclarativeBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, 0, parent) : 0;
244     if (cdata)
245         cdata->release();
246     if (typeData)
247         typeData->release();
248     return rv;
249 }
250
251 QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContext *ctxt, 
252                                          QObject *parent)
253 : QDeclarativeExpression(QDeclarativeContextData::get(ctxt), obj, str, *new QDeclarativeBindingPrivate)
254 {
255     setParent(parent);
256     setNotifyOnValueChanged(true);
257 }
258
259 QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContextData *ctxt, 
260                                          QObject *parent)
261 : QDeclarativeExpression(ctxt, obj, str, *new QDeclarativeBindingPrivate)
262 {
263     setParent(parent);
264     setNotifyOnValueChanged(true);
265 }
266
267 QDeclarativeBinding::QDeclarativeBinding(const QString &str, bool isRewritten, QObject *obj, 
268                                          QDeclarativeContextData *ctxt, 
269                                          const QString &url, int lineNumber, int columnNumber,
270                                          QObject *parent)
271 : QDeclarativeExpression(ctxt, obj, str, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeBindingPrivate)
272 {
273     Q_D(QDeclarativeBinding);
274
275     setParent(parent);
276     setNotifyOnValueChanged(true);
277 }
278
279 /*!  
280     \internal 
281
282     To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.  
283     For example:
284         v8::Handle<v8::Function> function;
285         new QDeclarativeBinding(&function, scope, ctxt);
286  */
287 QDeclarativeBinding::QDeclarativeBinding(void *functionPtr, QObject *obj, QDeclarativeContextData *ctxt, 
288                                          QObject *parent)
289 : QDeclarativeExpression(ctxt, obj, functionPtr, *new QDeclarativeBindingPrivate)
290 {
291     setParent(parent);
292     setNotifyOnValueChanged(true);
293 }
294
295 QDeclarativeBinding::~QDeclarativeBinding()
296 {
297 }
298
299 void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop)
300 {
301     Q_D(QDeclarativeBinding);
302     d->property = prop;
303
304     update();
305 }
306
307 void QDeclarativeBinding::setTarget(QObject *object,
308                                     const QDeclarativePropertyData &core,
309                                     QDeclarativeContextData *ctxt)
310 {
311     Q_D(QDeclarativeBinding);
312     d->property = QDeclarativePropertyPrivate::restore(object, core, ctxt);
313
314     update();
315 }
316
317 QDeclarativeProperty QDeclarativeBinding::property() const 
318 {
319    Q_D(const QDeclarativeBinding);
320    return d->property; 
321 }
322
323 void QDeclarativeBinding::setEvaluateFlags(EvaluateFlags flags)
324 {
325     Q_D(QDeclarativeBinding);
326     d->setRequiresThisObject(flags & RequiresThisObject);
327 }
328
329 QDeclarativeBinding::EvaluateFlags QDeclarativeBinding::evaluateFlags() const
330 {
331     Q_D(const QDeclarativeBinding);
332     return d->requiresThisObject()?RequiresThisObject:None;
333 }
334
335 void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
336 {
337     Q_D(QDeclarativeBinding);
338
339     if (!d->enabled || !d->context() || !d->context()->isValid()) 
340         return;
341
342     QDeclarativeTrace trace("General Binding Update");
343     trace.addDetail("URL", d->url);
344     trace.addDetail("Line", d->line);
345     trace.addDetail("Column", d->columnNumber);
346
347     if (!d->updating) {
348         QDeclarativeBindingProfiler prof(d->url, d->line, d->column);
349         prof.addDetail(expression());
350         d->updating = true;
351
352         QDeleteWatcher watcher(d);
353
354         if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
355
356             int idx = d->property.index();
357             Q_ASSERT(idx != -1);
358
359             QDeclarativeBinding *t = this;
360             int status = -1;
361             void *a[] = { &t, 0, &status, &flags };
362             QMetaObject::metacall(d->property.object(),
363                                   QMetaObject::WriteProperty,
364                                   idx, a);
365
366         } else {
367             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
368             ep->referenceScarceResources(); 
369
370             bool isUndefined = false;
371
372             v8::HandleScope handle_scope;
373             v8::Context::Scope scope(ep->v8engine()->context());
374             v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
375
376             trace.event("writing binding result");
377
378             bool needsErrorData = false;
379             if (!watcher.wasDeleted() && !d->error.isValid()) 
380                 needsErrorData = !QDeclarativePropertyPrivate::writeBinding(d->property, d, result, 
381                                                                             isUndefined, flags);
382
383             if (!watcher.wasDeleted()) {
384                
385                 if (needsErrorData) {
386                     QUrl url = QUrl(d->url);
387                     int line = d->line;
388                     if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
389
390                     d->error.setUrl(url);
391                     d->error.setLine(line);
392                     d->error.setColumn(-1);
393                 }
394
395                 if (d->error.isValid()) {
396                     if (!d->addError(ep)) ep->warning(this->error());
397                 } else {
398                     d->removeError();
399                 }
400
401             }
402
403             ep->dereferenceScarceResources(); 
404         }
405
406         if (!watcher.wasDeleted())
407             d->updating = false;
408     } else {
409         QDeclarativeBindingPrivate::printBindingLoopError(d->property);
410     }
411 }
412
413 void QDeclarativeBindingPrivate::printBindingLoopError(QDeclarativeProperty &prop)
414 {
415     qmlInfo(prop.object()) << QDeclarativeBinding::tr("Binding loop detected for property \"%1\"").arg(prop.name());
416 }
417
418 void QDeclarativeBindingPrivate::expressionChanged()
419 {
420     Q_Q(QDeclarativeBinding);
421     q->update();
422 }
423
424 void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
425 {
426     Q_D(QDeclarativeBinding);
427     d->enabled = e;
428     setNotifyOnValueChanged(e);
429
430     if (e) 
431         update(flags);
432 }
433
434 bool QDeclarativeBinding::enabled() const
435 {
436     Q_D(const QDeclarativeBinding);
437
438     return d->enabled;
439 }
440
441 QString QDeclarativeBinding::expression() const
442 {
443     return QDeclarativeExpression::expression();
444 }
445
446 QDeclarativeValueTypeProxyBinding::QDeclarativeValueTypeProxyBinding(QObject *o, int index)
447 : m_object(o), m_index(index), m_bindings(0)
448 {
449 }
450
451 QDeclarativeValueTypeProxyBinding::~QDeclarativeValueTypeProxyBinding()
452 {
453     while (m_bindings) {
454         QDeclarativeAbstractBinding *binding = m_bindings;
455         binding->setEnabled(false, 0);
456         binding->destroy();
457     }
458 }
459
460 void QDeclarativeValueTypeProxyBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
461 {
462     if (e) {
463         QDeclarativeAbstractBinding *bindings = m_bindings;
464         recursiveEnable(bindings, flags);
465     } else {
466         QDeclarativeAbstractBinding *bindings = m_bindings;
467         recursiveDisable(bindings);
468     }
469 }
470
471 void QDeclarativeValueTypeProxyBinding::recursiveEnable(QDeclarativeAbstractBinding *b, QDeclarativePropertyPrivate::WriteFlags flags)
472 {
473     if (!b)
474         return;
475
476     recursiveEnable(b->m_nextBinding, flags);
477
478     if (b)
479         b->setEnabled(true, flags);
480 }
481
482 void QDeclarativeValueTypeProxyBinding::recursiveDisable(QDeclarativeAbstractBinding *b)
483 {
484     if (!b)
485         return;
486
487     recursiveDisable(b->m_nextBinding);
488
489     if (b)
490         b->setEnabled(false, 0);
491 }
492
493 void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::WriteFlags)
494 {
495 }
496
497 QDeclarativeAbstractBinding *QDeclarativeValueTypeProxyBinding::binding(int propertyIndex)
498 {
499     QDeclarativeAbstractBinding *binding = m_bindings;
500     
501     while (binding && binding->propertyIndex() != propertyIndex) 
502         binding = binding->m_nextBinding;
503
504     return binding;
505 }
506
507 /*!
508 Removes a collection of bindings, corresponding to the set bits in \a mask.
509 */
510 void QDeclarativeValueTypeProxyBinding::removeBindings(quint32 mask)
511 {
512     QDeclarativeAbstractBinding *binding = m_bindings;
513     while (binding) {
514         if (mask & (1 << (binding->propertyIndex() >> 24))) {
515             QDeclarativeAbstractBinding *remove = binding;
516             binding = remove->m_nextBinding;
517             *remove->m_prevBinding = remove->m_nextBinding;
518             if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding;
519             remove->m_prevBinding = 0;
520             remove->m_nextBinding = 0;
521             remove->destroy();
522         } else {
523             binding = binding->m_nextBinding;
524         }
525     }
526 }
527
528 QT_END_NAMESPACE