5e2f655cdb4847af3a10cb5b0afa6819b38f58d7
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativebinding.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 "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
336 class QDeclarativeBindingProfiler {
337 public:
338     QDeclarativeBindingProfiler(QDeclarativeBinding *bind)
339     {
340         QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
341         QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Binding, bind->expression());
342         QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Binding, bind->sourceFile(), bind->lineNumber(), bind->columnNumber());
343     }
344
345     ~QDeclarativeBindingProfiler()
346     {
347         QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
348     }
349 };
350
351 void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
352 {
353     Q_D(QDeclarativeBinding);
354
355     if (!d->enabled || !d->context() || !d->context()->isValid()) 
356         return;
357
358     QDeclarativeTrace trace("General Binding Update");
359     trace.addDetail("URL", d->url);
360     trace.addDetail("Line", d->line);
361     trace.addDetail("Column", d->columnNumber);
362
363     if (!d->updating) {
364         QDeclarativeBindingProfiler prof(this);
365         d->updating = true;
366
367         QDeleteWatcher watcher(d);
368
369         if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
370
371             int idx = d->property.index();
372             Q_ASSERT(idx != -1);
373
374             QDeclarativeBinding *t = this;
375             int status = -1;
376             void *a[] = { &t, 0, &status, &flags };
377             QMetaObject::metacall(d->property.object(),
378                                   QMetaObject::WriteProperty,
379                                   idx, a);
380
381         } else {
382             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
383             ep->referenceScarceResources(); 
384
385             bool isUndefined = false;
386
387             v8::HandleScope handle_scope;
388             v8::Context::Scope scope(ep->v8engine()->context());
389             v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
390
391             trace.event("writing binding result");
392
393             bool needsErrorData = false;
394             if (!watcher.wasDeleted() && !d->error.isValid()) 
395                 needsErrorData = !QDeclarativePropertyPrivate::writeBinding(d->property, d, result, 
396                                                                             isUndefined, flags);
397
398             if (!watcher.wasDeleted()) {
399                
400                 if (needsErrorData) {
401                     QUrl url = QUrl(d->url);
402                     int line = d->line;
403                     if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
404
405                     d->error.setUrl(url);
406                     d->error.setLine(line);
407                     d->error.setColumn(-1);
408                 }
409
410                 if (d->error.isValid()) {
411                     if (!d->addError(ep)) ep->warning(this->error());
412                 } else {
413                     d->removeError();
414                 }
415
416             }
417
418             ep->dereferenceScarceResources(); 
419         }
420
421         if (!watcher.wasDeleted())
422             d->updating = false;
423     } else {
424         QDeclarativeBindingPrivate::printBindingLoopError(d->property);
425     }
426 }
427
428 void QDeclarativeBindingPrivate::printBindingLoopError(QDeclarativeProperty &prop)
429 {
430     qmlInfo(prop.object()) << QDeclarativeBinding::tr("Binding loop detected for property \"%1\"").arg(prop.name());
431 }
432
433 void QDeclarativeBindingPrivate::expressionChanged()
434 {
435     Q_Q(QDeclarativeBinding);
436     q->update();
437 }
438
439 void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
440 {
441     Q_D(QDeclarativeBinding);
442     d->enabled = e;
443     setNotifyOnValueChanged(e);
444
445     if (e) 
446         update(flags);
447 }
448
449 bool QDeclarativeBinding::enabled() const
450 {
451     Q_D(const QDeclarativeBinding);
452
453     return d->enabled;
454 }
455
456 QString QDeclarativeBinding::expression() const
457 {
458     return QDeclarativeExpression::expression();
459 }
460
461 QDeclarativeValueTypeProxyBinding::QDeclarativeValueTypeProxyBinding(QObject *o, int index)
462 : m_object(o), m_index(index), m_bindings(0)
463 {
464 }
465
466 QDeclarativeValueTypeProxyBinding::~QDeclarativeValueTypeProxyBinding()
467 {
468     while (m_bindings) {
469         QDeclarativeAbstractBinding *binding = m_bindings;
470         binding->setEnabled(false, 0);
471         binding->destroy();
472     }
473 }
474
475 void QDeclarativeValueTypeProxyBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
476 {
477     if (e) {
478         QDeclarativeAbstractBinding *bindings = m_bindings;
479         recursiveEnable(bindings, flags);
480     } else {
481         QDeclarativeAbstractBinding *bindings = m_bindings;
482         recursiveDisable(bindings);
483     }
484 }
485
486 void QDeclarativeValueTypeProxyBinding::recursiveEnable(QDeclarativeAbstractBinding *b, QDeclarativePropertyPrivate::WriteFlags flags)
487 {
488     if (!b)
489         return;
490
491     recursiveEnable(b->m_nextBinding, flags);
492
493     if (b)
494         b->setEnabled(true, flags);
495 }
496
497 void QDeclarativeValueTypeProxyBinding::recursiveDisable(QDeclarativeAbstractBinding *b)
498 {
499     if (!b)
500         return;
501
502     recursiveDisable(b->m_nextBinding);
503
504     if (b)
505         b->setEnabled(false, 0);
506 }
507
508 void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::WriteFlags)
509 {
510 }
511
512 QDeclarativeAbstractBinding *QDeclarativeValueTypeProxyBinding::binding(int propertyIndex)
513 {
514     QDeclarativeAbstractBinding *binding = m_bindings;
515     
516     while (binding && binding->propertyIndex() != propertyIndex) 
517         binding = binding->m_nextBinding;
518
519     return binding;
520 }
521
522 /*!
523 Removes a collection of bindings, corresponding to the set bits in \a mask.
524 */
525 void QDeclarativeValueTypeProxyBinding::removeBindings(quint32 mask)
526 {
527     QDeclarativeAbstractBinding *binding = m_bindings;
528     while (binding) {
529         if (mask & (1 << (binding->propertyIndex() >> 24))) {
530             QDeclarativeAbstractBinding *remove = binding;
531             binding = remove->m_nextBinding;
532             *remove->m_prevBinding = remove->m_nextBinding;
533             if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding;
534             remove->m_prevBinding = 0;
535             remove->m_nextBinding = 0;
536             remove->destroy();
537         } else {
538             binding = binding->m_nextBinding;
539         }
540     }
541 }
542
543 QT_END_NAMESPACE