1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
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.
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.
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.
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.
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;
335 void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
337 Q_D(QDeclarativeBinding);
339 if (!d->enabled || !d->context() || !d->context()->isValid())
342 QDeclarativeTrace trace("General Binding Update");
343 trace.addDetail("URL", d->url);
344 trace.addDetail("Line", d->line);
345 trace.addDetail("Column", d->columnNumber);
348 QDeclarativeBindingProfiler prof(d->url, d->line, d->column);
349 prof.addDetail(expression());
352 QDeleteWatcher watcher(d);
354 if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
356 int idx = d->property.index();
359 QDeclarativeBinding *t = this;
361 void *a[] = { &t, 0, &status, &flags };
362 QMetaObject::metacall(d->property.object(),
363 QMetaObject::WriteProperty,
367 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
368 ep->referenceScarceResources();
370 bool isUndefined = false;
372 v8::HandleScope handle_scope;
373 v8::Context::Scope scope(ep->v8engine()->context());
374 v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
376 trace.event("writing binding result");
378 bool needsErrorData = false;
379 if (!watcher.wasDeleted() && !d->error.isValid())
380 needsErrorData = !QDeclarativePropertyPrivate::writeBinding(d->property, d, result,
383 if (!watcher.wasDeleted()) {
385 if (needsErrorData) {
386 QUrl url = QUrl(d->url);
388 if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
390 d->error.setUrl(url);
391 d->error.setLine(line);
392 d->error.setColumn(-1);
395 if (d->error.isValid()) {
396 if (!d->addError(ep)) ep->warning(this->error());
403 ep->dereferenceScarceResources();
406 if (!watcher.wasDeleted())
409 QDeclarativeBindingPrivate::printBindingLoopError(d->property);
413 void QDeclarativeBindingPrivate::printBindingLoopError(QDeclarativeProperty &prop)
415 qmlInfo(prop.object()) << QDeclarativeBinding::tr("Binding loop detected for property \"%1\"").arg(prop.name());
418 void QDeclarativeBindingPrivate::expressionChanged()
420 Q_Q(QDeclarativeBinding);
424 void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
426 Q_D(QDeclarativeBinding);
428 setNotifyOnValueChanged(e);
434 bool QDeclarativeBinding::enabled() const
436 Q_D(const QDeclarativeBinding);
441 QString QDeclarativeBinding::expression() const
443 return QDeclarativeExpression::expression();
446 QDeclarativeValueTypeProxyBinding::QDeclarativeValueTypeProxyBinding(QObject *o, int index)
447 : m_object(o), m_index(index), m_bindings(0)
451 QDeclarativeValueTypeProxyBinding::~QDeclarativeValueTypeProxyBinding()
454 QDeclarativeAbstractBinding *binding = m_bindings;
455 binding->setEnabled(false, 0);
460 void QDeclarativeValueTypeProxyBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
463 QDeclarativeAbstractBinding *bindings = m_bindings;
464 recursiveEnable(bindings, flags);
466 QDeclarativeAbstractBinding *bindings = m_bindings;
467 recursiveDisable(bindings);
471 void QDeclarativeValueTypeProxyBinding::recursiveEnable(QDeclarativeAbstractBinding *b, QDeclarativePropertyPrivate::WriteFlags flags)
476 recursiveEnable(b->m_nextBinding, flags);
479 b->setEnabled(true, flags);
482 void QDeclarativeValueTypeProxyBinding::recursiveDisable(QDeclarativeAbstractBinding *b)
487 recursiveDisable(b->m_nextBinding);
490 b->setEnabled(false, 0);
493 void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::WriteFlags)
497 QDeclarativeAbstractBinding *QDeclarativeValueTypeProxyBinding::binding(int propertyIndex)
499 QDeclarativeAbstractBinding *binding = m_bindings;
501 while (binding && binding->propertyIndex() != propertyIndex)
502 binding = binding->m_nextBinding;
508 Removes a collection of bindings, corresponding to the set bits in \a mask.
510 void QDeclarativeValueTypeProxyBinding::removeBindings(quint32 mask)
512 QDeclarativeAbstractBinding *binding = m_bindings;
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;
523 binding = binding->m_nextBinding;