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 QtQml 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 "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>
55 #include <QtCore/qdebug.h>
59 // Used in qqmlabstractbinding.cpp
60 QQmlAbstractBinding::VTable QQmlBinding_vtable = {
61 QQmlAbstractBinding::default_destroy<QQmlBinding>,
62 QQmlBinding::expression,
63 QQmlBinding::propertyIndex,
65 QQmlBinding::setEnabled,
67 QQmlBinding::retargetBinding
70 QQmlBinding::Identifier QQmlBinding::Invalid = -1;
73 QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
74 const QString &url, int lineNumber)
81 QQmlContextData *ctxtdata = QQmlContextData::get(ctxt);
82 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine());
83 if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
84 QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
87 if (QQmlCompiledData *cdata = typeData->compiledData()) {
88 rv = new QQmlBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, 0);
97 static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = {
98 QQmlBinding::expressionIdentifier,
99 QQmlBinding::expressionChanged
102 QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt)
103 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
104 m_lineNumber(-1), m_columnNumber(-1)
106 setNotifyOnValueChanged(true);
107 QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt));
110 QQmlRewrite::RewriteBinding rewriteBinding;
111 QString code = rewriteBinding(str);
113 m_expression = str.toUtf8();
114 v8function = evalFunction(context(), obj, code, QString(), 0);
117 QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt)
118 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
119 m_lineNumber(-1), m_columnNumber(-1)
121 setNotifyOnValueChanged(true);
122 QQmlAbstractExpression::setContext(ctxt);
125 QQmlRewrite::RewriteBinding rewriteBinding;
126 QString code = rewriteBinding(str);
128 m_expression = str.toUtf8();
129 v8function = evalFunction(ctxt, obj, code, QString(), 0);
132 QQmlBinding::QQmlBinding(const QString &str, bool isRewritten, QObject *obj,
133 QQmlContextData *ctxt,
134 const QString &url, int lineNumber, int columnNumber)
135 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
136 m_lineNumber(-1), m_columnNumber(-1)
138 setNotifyOnValueChanged(true);
139 QQmlAbstractExpression::setContext(ctxt);
146 QQmlRewrite::RewriteBinding rewriteBinding;
147 code = rewriteBinding(str);
151 m_lineNumber = lineNumber;
152 m_columnNumber = columnNumber;
153 m_expression = str.toUtf8();
155 v8function = evalFunction(ctxt, obj, code, url, lineNumber);
161 To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
163 v8::Handle<v8::Function> function;
164 new QQmlBinding(&function, scope, ctxt);
166 QQmlBinding::QQmlBinding(void *functionPtr, QObject *obj, QQmlContextData *ctxt,
167 const QString &url, int lineNumber, int columnNumber)
168 : QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
169 m_url(url), m_lineNumber(lineNumber), m_columnNumber(columnNumber)
171 setNotifyOnValueChanged(true);
172 QQmlAbstractExpression::setContext(ctxt);
175 v8function = qPersistentNew<v8::Function>(*(v8::Handle<v8::Function> *)functionPtr);
178 QQmlBinding::~QQmlBinding()
180 qPersistentDispose(v8function);
183 void QQmlBinding::setEvaluateFlags(EvaluateFlags flags)
185 setRequiresThisObject(flags & RequiresThisObject);
188 QQmlBinding::EvaluateFlags QQmlBinding::evaluateFlags() const
190 return requiresThisObject()?RequiresThisObject:None;
193 void QQmlBinding::setNotifyOnValueChanged(bool v)
195 QQmlJavaScriptExpression::setNotifyOnValueChanged(v);
198 void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
200 if (!enabledFlag() || !context() || !context()->isValid())
203 // Check that the target has not been deleted
204 if (QQmlData::wasDeleted(object()))
207 QQmlTrace trace("General Binding Update");
208 trace.addDetail("URL", m_url);
209 trace.addDetail("Line", m_lineNumber);
210 trace.addDetail("Column", m_columnNumber);
212 if (!updatingFlag()) {
213 QQmlBindingProfiler prof(m_url, m_lineNumber, m_columnNumber, QQmlProfilerService::QmlBinding);
214 setUpdatingFlag(true);
216 QQmlAbstractExpression::DeleteWatcher watcher(this);
218 if (m_core.propType == qMetaTypeId<QQmlBinding *>()) {
220 int idx = m_core.coreIndex;
223 QQmlBinding *t = this;
225 void *a[] = { &t, 0, &status, &flags };
226 QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a);
229 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
230 ep->referenceScarceResources();
232 bool isUndefined = false;
234 v8::HandleScope handle_scope;
235 v8::Context::Scope scope(ep->v8engine()->context());
236 v8::Local<v8::Value> result =
237 QQmlJavaScriptExpression::evaluate(context(), v8function, &isUndefined);
239 trace.event("writing binding result");
241 bool needsErrorData = false;
242 if (!watcher.wasDeleted() && !hasError())
243 needsErrorData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(),
244 this, result, isUndefined, flags);
246 if (!watcher.wasDeleted()) {
248 if (needsErrorData) {
249 QUrl url = QUrl(m_url);
251 delayedError()->error.setUrl(url);
252 delayedError()->error.setLine(m_lineNumber);
253 delayedError()->error.setColumn(m_columnNumber);
257 if (!delayedError()->addError(ep)) ep->warning(this->error());
264 ep->dereferenceScarceResources();
267 if (!watcher.wasDeleted())
268 setUpdatingFlag(false);
270 QQmlProperty p = property();
271 QQmlAbstractBinding::printBindingLoopError(p);
275 QVariant QQmlBinding::evaluate()
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 ep->dereferenceScarceResources();
289 return ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
292 QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e)
294 QQmlBinding *This = static_cast<QQmlBinding *>(e);
296 return QLatin1Char('"') + QString::fromUtf8(This->m_expression) + QLatin1Char('"');
299 void QQmlBinding::expressionChanged(QQmlJavaScriptExpression *e)
301 QQmlBinding *This = static_cast<QQmlBinding *>(e);
305 void QQmlBinding::refresh()
310 QString QQmlBinding::expression(const QQmlAbstractBinding *This)
312 return static_cast<const QQmlBinding *>(This)->expression();
315 int QQmlBinding::propertyIndex(const QQmlAbstractBinding *This)
317 return static_cast<const QQmlBinding *>(This)->propertyIndex();
320 QObject *QQmlBinding::object(const QQmlAbstractBinding *This)
322 return static_cast<const QQmlBinding *>(This)->object();
325 void QQmlBinding::setEnabled(QQmlAbstractBinding *This, bool e, QQmlPropertyPrivate::WriteFlags f)
327 static_cast<QQmlBinding *>(This)->setEnabled(e, f);
330 void QQmlBinding::update(QQmlAbstractBinding *This , QQmlPropertyPrivate::WriteFlags f)
332 static_cast<QQmlBinding *>(This)->update(f);
335 void QQmlBinding::retargetBinding(QQmlAbstractBinding *This, QObject *o, int i)
337 static_cast<QQmlBinding *>(This)->retargetBinding(o, i);
340 void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
343 setNotifyOnValueChanged(e);
349 QString QQmlBinding::expression() const
351 return QString::fromUtf8(m_expression);
354 QObject *QQmlBinding::object() const
356 if (m_coreObject.hasValue()) return m_coreObject.constValue()->target;
357 else return *m_coreObject;
360 int QQmlBinding::propertyIndex() const
362 if (m_coreObject.hasValue()) return m_coreObject.constValue()->targetProperty;
363 else return m_core.encodedIndex();
366 void QQmlBinding::retargetBinding(QObject *t, int i)
368 m_coreObject.value().target = t;
369 m_coreObject.value().targetProperty = i;
372 void QQmlBinding::setTarget(const QQmlProperty &prop)
374 setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core,
375 QQmlPropertyPrivate::get(prop)->context);
378 void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, QQmlContextData *ctxt)
380 m_coreObject = object;
385 QQmlProperty QQmlBinding::property() const
387 return QQmlPropertyPrivate::restore(object(), m_core, *m_ctxt);