1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qdeclarativebinding_p.h"
43 #include "qdeclarativebinding_p_p.h"
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>
54 #include <QtCore/qdebug.h>
58 QDeclarativeAbstractBinding::QDeclarativeAbstractBinding()
59 : m_object(0), m_propertyIndex(-1), m_mePtr(0), m_prevBinding(0), m_nextBinding(0)
63 QDeclarativeAbstractBinding::~QDeclarativeAbstractBinding()
65 Q_ASSERT(m_prevBinding == 0);
66 Q_ASSERT(m_mePtr == 0);
70 Destroy the binding. Use this instead of calling delete.
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
76 void QDeclarativeAbstractBinding::destroy()
85 Add this binding to \a object.
87 This transfers ownership of the binding to the object, marks the object's property as
90 However, it does not enable the binding itself or call update() on it.
92 void QDeclarativeAbstractBinding::addToObject(QObject *object, int index)
96 if (m_object == object && m_propertyIndex == index)
101 Q_ASSERT(!m_prevBinding);
104 m_propertyIndex = index;
106 QDeclarativeData *data = QDeclarativeData::get(object, true);
108 if (index & 0xFF000000) {
111 int coreIndex = index & 0xFFFFFF;
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);
124 proxy = new QDeclarativeValueTypeProxyBinding(object, coreIndex);
125 proxy->addToObject(object, coreIndex);
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;
134 m_nextBinding = data->bindings;
135 if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
136 m_prevBinding = &data->bindings;
137 data->bindings = this;
139 data->setBindingBit(m_object, index);
144 Remove the binding from the object.
146 void QDeclarativeAbstractBinding::removeFromObject()
149 int index = propertyIndex();
151 *m_prevBinding = m_nextBinding;
152 if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding;
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);
166 m_propertyIndex = -1;
170 static void bindingDummyDeleter(QDeclarativeAbstractBinding *)
174 QDeclarativeAbstractBinding::Pointer QDeclarativeAbstractBinding::weakPointer()
176 if (m_selfPointer.isNull())
177 m_selfPointer = QSharedPointer<QDeclarativeAbstractBinding>(this, bindingDummyDeleter);
179 return m_selfPointer.toWeakRef();
182 void QDeclarativeAbstractBinding::clear()
190 QString QDeclarativeAbstractBinding::expression() const
192 return QLatin1String("<Unknown>");
195 QObject *QDeclarativeAbstractBinding::object() const
200 int QDeclarativeAbstractBinding::propertyIndex() const
202 return m_propertyIndex;
205 void QDeclarativeAbstractBinding::setEnabled(bool enabled, QDeclarativePropertyPrivate::WriteFlags flags)
207 if (enabled) update(flags);
210 QDeclarativeBinding::Identifier QDeclarativeBinding::Invalid = -1;
212 void QDeclarativeBindingPrivate::refresh()
214 Q_Q(QDeclarativeBinding);
218 QDeclarativeBindingPrivate::QDeclarativeBindingPrivate()
219 : updating(false), enabled(false)
223 QDeclarativeBindingPrivate::~QDeclarativeBindingPrivate()
227 QDeclarativeBinding *
228 QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeContext *ctxt,
229 const QString &url, int lineNumber, QObject *parent)
234 QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(ctxt);
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();
243 QDeclarativeBinding *rv = cdata ? new QDeclarativeBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, 0, parent) : 0;
251 QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContext *ctxt,
253 : QDeclarativeExpression(QDeclarativeContextData::get(ctxt), obj, str, *new QDeclarativeBindingPrivate)
256 setNotifyOnValueChanged(true);
259 QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContextData *ctxt,
261 : QDeclarativeExpression(ctxt, obj, str, *new QDeclarativeBindingPrivate)
264 setNotifyOnValueChanged(true);
267 QDeclarativeBinding::QDeclarativeBinding(const QString &str, bool isRewritten, QObject *obj,
268 QDeclarativeContextData *ctxt,
269 const QString &url, int lineNumber, int columnNumber,
271 : QDeclarativeExpression(ctxt, obj, str, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeBindingPrivate)
273 Q_D(QDeclarativeBinding);
276 setNotifyOnValueChanged(true);
282 To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
284 v8::Handle<v8::Function> function;
285 new QDeclarativeBInding(&function, scope, ctxt);
287 QDeclarativeBinding::QDeclarativeBinding(void *functionPtr, QObject *obj, QDeclarativeContextData *ctxt,
289 : QDeclarativeExpression(ctxt, obj, functionPtr, *new QDeclarativeBindingPrivate)
292 setNotifyOnValueChanged(true);
295 QDeclarativeBinding::~QDeclarativeBinding()
299 void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop)
301 Q_D(QDeclarativeBinding);
307 void QDeclarativeBinding::setTarget(QObject *object,
308 const QDeclarativePropertyData &core,
309 QDeclarativeContextData *ctxt)
311 Q_D(QDeclarativeBinding);
312 d->property = QDeclarativePropertyPrivate::restore(object, core, ctxt);
317 QDeclarativeProperty QDeclarativeBinding::property() const
319 Q_D(const QDeclarativeBinding);
323 void QDeclarativeBinding::setEvaluateFlags(EvaluateFlags flags)
325 Q_D(QDeclarativeBinding);
326 d->setRequiresThisObject(flags & RequiresThisObject);
329 QDeclarativeBinding::EvaluateFlags QDeclarativeBinding::evaluateFlags() const
331 Q_D(const QDeclarativeBinding);
332 return d->requiresThisObject()?RequiresThisObject:None;
336 class QDeclarativeBindingProfiler {
338 QDeclarativeBindingProfiler(QDeclarativeBinding *bind)
340 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
341 QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Binding, bind->expression());
342 QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Binding, bind->sourceFile(), bind->lineNumber(), bind->columnNumber());
345 ~QDeclarativeBindingProfiler()
347 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
351 void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
353 Q_D(QDeclarativeBinding);
355 if (!d->enabled || !d->context() || !d->context()->isValid())
358 QDeclarativeTrace trace("General Binding Update");
359 trace.addDetail("URL", d->url);
360 trace.addDetail("Line", d->line);
361 trace.addDetail("Column", d->columnNumber);
364 QDeclarativeBindingProfiler prof(this);
367 QDeleteWatcher watcher(d);
369 if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
371 int idx = d->property.index();
374 QDeclarativeBinding *t = this;
376 void *a[] = { &t, 0, &status, &flags };
377 QMetaObject::metacall(d->property.object(),
378 QMetaObject::WriteProperty,
382 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
383 ep->referenceScarceResources();
385 bool isUndefined = false;
387 v8::HandleScope handle_scope;
388 v8::Context::Scope scope(ep->v8engine()->context());
389 v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
391 trace.event("writing binding result");
393 bool needsErrorData = false;
394 if (!watcher.wasDeleted() && !d->error.isValid())
395 needsErrorData = !QDeclarativePropertyPrivate::writeBinding(d->property, d, result,
398 if (!watcher.wasDeleted()) {
400 if (needsErrorData) {
401 QUrl url = QUrl(d->url);
403 if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
405 d->error.setUrl(url);
406 d->error.setLine(line);
407 d->error.setColumn(-1);
410 if (d->error.isValid()) {
411 if (!d->addError(ep)) ep->warning(this->error());
418 ep->dereferenceScarceResources();
421 if (!watcher.wasDeleted())
424 QDeclarativeBindingPrivate::printBindingLoopError(d->property);
428 void QDeclarativeBindingPrivate::printBindingLoopError(QDeclarativeProperty &prop)
430 qmlInfo(prop.object()) << QDeclarativeBinding::tr("Binding loop detected for property \"%1\"").arg(prop.name());
433 void QDeclarativeBindingPrivate::expressionChanged()
435 Q_Q(QDeclarativeBinding);
439 void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
441 Q_D(QDeclarativeBinding);
443 setNotifyOnValueChanged(e);
449 bool QDeclarativeBinding::enabled() const
451 Q_D(const QDeclarativeBinding);
456 QString QDeclarativeBinding::expression() const
458 return QDeclarativeExpression::expression();
461 QDeclarativeValueTypeProxyBinding::QDeclarativeValueTypeProxyBinding(QObject *o, int index)
462 : m_object(o), m_index(index), m_bindings(0)
466 QDeclarativeValueTypeProxyBinding::~QDeclarativeValueTypeProxyBinding()
469 QDeclarativeAbstractBinding *binding = m_bindings;
470 binding->setEnabled(false, 0);
475 void QDeclarativeValueTypeProxyBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
478 QDeclarativeAbstractBinding *bindings = m_bindings;
479 recursiveEnable(bindings, flags);
481 QDeclarativeAbstractBinding *bindings = m_bindings;
482 recursiveDisable(bindings);
486 void QDeclarativeValueTypeProxyBinding::recursiveEnable(QDeclarativeAbstractBinding *b, QDeclarativePropertyPrivate::WriteFlags flags)
491 recursiveEnable(b->m_nextBinding, flags);
494 b->setEnabled(true, flags);
497 void QDeclarativeValueTypeProxyBinding::recursiveDisable(QDeclarativeAbstractBinding *b)
502 recursiveDisable(b->m_nextBinding);
505 b->setEnabled(false, 0);
508 void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::WriteFlags)
512 QDeclarativeAbstractBinding *QDeclarativeValueTypeProxyBinding::binding(int propertyIndex)
514 QDeclarativeAbstractBinding *binding = m_bindings;
516 while (binding && binding->propertyIndex() != propertyIndex)
517 binding = binding->m_nextBinding;
523 Removes a collection of bindings, corresponding to the set bits in \a mask.
525 void QDeclarativeValueTypeProxyBinding::removeBindings(quint32 mask)
527 QDeclarativeAbstractBinding *binding = m_bindings;
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;
538 binding = binding->m_nextBinding;