1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qqmlbinding_p.h"
45 #include "qqmlcontext.h"
47 #include "qqmlcompiler_p.h"
48 #include "qqmldata_p.h"
49 #include <private/qqmlprofilerservice_p.h>
50 #include <private/qqmltrace_p.h>
51 #include <private/qqmlexpression_p.h>
52 #include <private/qqmlrewrite_p.h>
53 #include <private/qqmlscriptstring_p.h>
56 #include <QtCore/qdebug.h>
60 // Used in qqmlabstractbinding.cpp
61 QQmlAbstractBinding::VTable QQmlBinding_vtable = {
62 QQmlAbstractBinding::default_destroy<QQmlBinding>,
63 QQmlBinding::expression,
64 QQmlBinding::propertyIndex,
66 QQmlBinding::setEnabled,
68 QQmlBinding::retargetBinding
71 QQmlBinding::Identifier QQmlBinding::Invalid = -1;
74 QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
75 const QString &url, quint16 lineNumber)
82 QQmlContextData *ctxtdata = QQmlContextData::get(ctxt);
83 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine());
84 if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
85 QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
88 if (QQmlCompiledData *cdata = typeData->compiledData()) {
89 rv = new QQmlBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, 0);
98 static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = {
99 QQmlBinding::expressionIdentifier,
100 QQmlBinding::expressionChanged
103 QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt)
104 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
105 m_lineNumber(0), m_columnNumber(0)
107 setNotifyOnValueChanged(true);
108 QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt));
111 QQmlRewrite::RewriteBinding rewriteBinding;
112 QString code = rewriteBinding(str);
114 m_expression = str.toUtf8();
115 v8function = evalFunction(context(), obj, code, QString(), 0);
118 QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
119 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding)
121 if (ctxt && !ctxt->isValid())
124 const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
125 if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
128 bool needRewrite = true;
131 int id = scriptPrivate->bindingId;
133 QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
134 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
135 if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
136 QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
139 if (QQmlCompiledData *cdata = typeData->compiledData()) {
141 code = cdata->primitives.at(id);
150 QQmlRewrite::RewriteBinding rewriteBinding;
151 code = rewriteBinding(scriptPrivate->script);
154 setNotifyOnValueChanged(true);
155 QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
156 setScopeObject(obj ? obj : scriptPrivate->scope);
158 m_expression = scriptPrivate->script.toUtf8();
159 m_lineNumber = scriptPrivate->lineNumber;
160 m_columnNumber = scriptPrivate->columnNumber;
162 v8function = evalFunction(context(), scopeObject(), code, QString(), m_lineNumber);
165 QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt)
166 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
167 m_lineNumber(0), m_columnNumber(0)
169 setNotifyOnValueChanged(true);
170 QQmlAbstractExpression::setContext(ctxt);
173 QQmlRewrite::RewriteBinding rewriteBinding;
174 QString code = rewriteBinding(str);
176 m_expression = str.toUtf8();
177 v8function = evalFunction(ctxt, obj, code, QString(), 0);
180 QQmlBinding::QQmlBinding(const QString &str, bool isRewritten, QObject *obj,
181 QQmlContextData *ctxt,
182 const QString &url, quint16 lineNumber, quint16 columnNumber)
183 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
184 m_url(url), m_lineNumber(lineNumber), m_columnNumber(columnNumber)
186 setNotifyOnValueChanged(true);
187 QQmlAbstractExpression::setContext(ctxt);
194 QQmlRewrite::RewriteBinding rewriteBinding;
195 code = rewriteBinding(str);
198 m_expression = str.toUtf8();
200 v8function = evalFunction(ctxt, obj, code, url, m_lineNumber);
206 To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
208 v8::Handle<v8::Function> function;
209 new QQmlBinding(&function, scope, ctxt);
211 QQmlBinding::QQmlBinding(void *functionPtr, QObject *obj, QQmlContextData *ctxt,
212 const QString &url, quint16 lineNumber, quint16 columnNumber)
213 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
214 m_url(url), m_lineNumber(lineNumber), m_columnNumber(columnNumber)
216 setNotifyOnValueChanged(true);
217 QQmlAbstractExpression::setContext(ctxt);
220 v8function = qPersistentNew<v8::Function>(*(v8::Handle<v8::Function> *)functionPtr);
223 QQmlBinding::~QQmlBinding()
225 qPersistentDispose(v8function);
228 void QQmlBinding::setEvaluateFlags(EvaluateFlags flags)
230 setRequiresThisObject(flags & RequiresThisObject);
233 QQmlBinding::EvaluateFlags QQmlBinding::evaluateFlags() const
235 return requiresThisObject()?RequiresThisObject:None;
238 void QQmlBinding::setNotifyOnValueChanged(bool v)
240 QQmlJavaScriptExpression::setNotifyOnValueChanged(v);
243 void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
245 if (!enabledFlag() || !context() || !context()->isValid())
248 // Check that the target has not been deleted
249 if (QQmlData::wasDeleted(object()))
252 int lineNo = qmlSourceCoordinate(m_lineNumber);
253 int columnNo = qmlSourceCoordinate(m_columnNumber);
255 QQmlTrace trace("General Binding Update");
256 trace.addDetail("URL", m_url);
257 trace.addDetail("Line", lineNo);
258 trace.addDetail("Column", columnNo);
260 if (!updatingFlag()) {
261 QQmlBindingProfiler prof(m_url, lineNo, columnNo, QQmlProfilerService::QmlBinding);
262 setUpdatingFlag(true);
264 QQmlAbstractExpression::DeleteWatcher watcher(this);
266 if (m_core.propType == qMetaTypeId<QQmlBinding *>()) {
268 int idx = m_core.coreIndex;
271 QQmlBinding *t = this;
273 void *a[] = { &t, 0, &status, &flags };
274 QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a);
277 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
278 ep->referenceScarceResources();
280 bool isUndefined = false;
282 v8::HandleScope handle_scope;
283 v8::Context::Scope scope(ep->v8engine()->context());
284 v8::Local<v8::Value> result =
285 QQmlJavaScriptExpression::evaluate(context(), v8function, &isUndefined);
287 trace.event("writing binding result");
289 bool needsErrorLocationData = false;
290 if (!watcher.wasDeleted() && !hasError())
291 needsErrorLocationData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(),
292 this, result, isUndefined, flags);
294 if (!watcher.wasDeleted()) {
296 if (needsErrorLocationData)
297 delayedError()->setErrorLocation(QUrl(m_url), m_lineNumber, m_columnNumber);
300 if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine));
307 ep->dereferenceScarceResources();
310 if (!watcher.wasDeleted())
311 setUpdatingFlag(false);
313 QQmlProperty p = property();
314 QQmlAbstractBinding::printBindingLoopError(p);
318 QVariant QQmlBinding::evaluate()
320 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
321 ep->referenceScarceResources();
323 bool isUndefined = false;
325 v8::HandleScope handle_scope;
326 v8::Context::Scope scope(ep->v8engine()->context());
327 v8::Local<v8::Value> result =
328 QQmlJavaScriptExpression::evaluate(context(), v8function, &isUndefined);
330 ep->dereferenceScarceResources();
332 return ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
335 QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e)
337 QQmlBinding *This = static_cast<QQmlBinding *>(e);
339 return QLatin1Char('"') + QString::fromUtf8(This->m_expression) + QLatin1Char('"');
342 void QQmlBinding::expressionChanged(QQmlJavaScriptExpression *e)
344 QQmlBinding *This = static_cast<QQmlBinding *>(e);
348 void QQmlBinding::refresh()
353 QString QQmlBinding::expression(const QQmlAbstractBinding *This)
355 return static_cast<const QQmlBinding *>(This)->expression();
358 int QQmlBinding::propertyIndex(const QQmlAbstractBinding *This)
360 return static_cast<const QQmlBinding *>(This)->propertyIndex();
363 QObject *QQmlBinding::object(const QQmlAbstractBinding *This)
365 return static_cast<const QQmlBinding *>(This)->object();
368 void QQmlBinding::setEnabled(QQmlAbstractBinding *This, bool e, QQmlPropertyPrivate::WriteFlags f)
370 static_cast<QQmlBinding *>(This)->setEnabled(e, f);
373 void QQmlBinding::update(QQmlAbstractBinding *This , QQmlPropertyPrivate::WriteFlags f)
375 static_cast<QQmlBinding *>(This)->update(f);
378 void QQmlBinding::retargetBinding(QQmlAbstractBinding *This, QObject *o, int i)
380 static_cast<QQmlBinding *>(This)->retargetBinding(o, i);
383 void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
386 setNotifyOnValueChanged(e);
392 QString QQmlBinding::expression() const
394 return QString::fromUtf8(m_expression);
397 QObject *QQmlBinding::object() const
399 if (m_coreObject.hasValue()) return m_coreObject.constValue()->target;
400 else return *m_coreObject;
403 int QQmlBinding::propertyIndex() const
405 if (m_coreObject.hasValue()) return m_coreObject.constValue()->targetProperty;
406 else return m_core.encodedIndex();
409 void QQmlBinding::retargetBinding(QObject *t, int i)
411 m_coreObject.value().target = t;
412 m_coreObject.value().targetProperty = i;
415 void QQmlBinding::setTarget(const QQmlProperty &prop)
417 setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core,
418 QQmlPropertyPrivate::get(prop)->context);
421 void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, QQmlContextData *ctxt)
423 m_coreObject = object;
428 QQmlProperty QQmlBinding::property() const
430 return QQmlPropertyPrivate::restore(object(), m_core, *m_ctxt);