210 QQmlEnginePrivate *ep;
214QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData,
bool *isUndefined)
216 QQmlEngine *qmlEngine = engine();
217 QV4::Function *v4Function = function();
218 if (!v4Function || !qmlEngine) {
221 return QV4::Encode::undefined();
226 QQmlJavaScriptExpressionCapture capture(
this, qmlEngine);
228 QV4::Scope scope(qmlEngine->handle());
230 if (QObject *thisObject = scopeObject()) {
231 callData->thisObject = QV4::QObjectWrapper::wrap(scope.engine, thisObject);
232 if (callData->thisObject.isNullOrUndefined())
233 callData->thisObject = scope.engine->globalObject;
235 callData->thisObject = scope.engine->globalObject;
238 Q_ASSERT(m_qmlScope.valueRef());
239 QV4::ScopedValue result(scope, v4Function->call(
240 &(callData->thisObject.asValue<QV4::Value>()),
241 callData->argValues<QV4::Value>(), callData->argc(),
242 static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef())));
244 if (capture.catchException(scope)) {
247 }
else if (isUndefined) {
248 *isUndefined = result->isUndefined();
251 return result->asReturnedValue();
254bool QQmlJavaScriptExpression::evaluate(
void **a,
const QMetaType *types,
int argc)
258 QQmlEngine *qmlEngine = engine();
265 QQmlJavaScriptExpressionCapture capture(
this, qmlEngine);
267 QV4::Scope scope(qmlEngine->handle());
269 Q_ASSERT(m_qmlScope.valueRef());
270 Q_ASSERT(function());
271 const bool resultIsDefined = function()->call(
272 scopeObject(), a, types, argc,
273 static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
275 return !capture.catchException(scope) && resultIsDefined;
278void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
280 if (watcher->wasDeleted())
283 Q_ASSERT(expression);
285 while (!guards.isEmpty() && !guards.first()->isConnected(n))
286 guards.takeFirst()->Delete();
288 QQmlJavaScriptExpressionGuard *g =
nullptr;
289 if (!guards.isEmpty()) {
290 g = guards.takeFirst();
292 Q_ASSERT(g->isConnected(n));
294 g = QQmlJavaScriptExpressionGuard::New(expression, engine);
298 expression->activeGuards.prepend(g);
302
303
304
305void QQmlPropertyCapture::captureProperty(QObject *o,
int c,
int n,
bool doNotify)
307 if (watcher->wasDeleted())
310 Q_ASSERT(expression);
315 const QQmlData *ddata = QQmlData::get(o,
false);
316 const QMetaObject *metaObjectForBindable =
nullptr;
317 if (
auto const propCache = (ddata ? ddata->propertyCache.data() :
nullptr)) {
318 Q_ASSERT(propCache->property(c));
319 if (propCache->property(c)->notifiesViaBindable())
320 metaObjectForBindable = propCache->metaObject();
322 const QMetaObject *m = o->metaObject();
323 if (m->property(c).isBindable())
324 metaObjectForBindable = m;
326 if (metaObjectForBindable) {
327 captureBindableProperty(o, metaObjectForBindable, c);
332 captureNonBindableProperty(o, n, c, doNotify);
335void QQmlPropertyCapture::captureProperty(
336 QObject *o,
const QQmlPropertyCache *propertyCache,
const QQmlPropertyData *propertyData,
339 if (watcher->wasDeleted())
342 Q_ASSERT(expression);
344 if (propertyData->notifiesViaBindable()) {
345 if (
const QMetaObject *metaObjectForBindable = propertyCache->metaObject()) {
346 captureBindableProperty(o, metaObjectForBindable, propertyData->coreIndex());
351 captureNonBindableProperty(o, propertyData->notifyIndex(), propertyData->coreIndex(), doNotify);
354bool QQmlJavaScriptExpression::needsPropertyChangeTrigger(QObject *target,
int propertyIndex)
356 TriggerList **prev = &qpropertyChangeTriggers;
357 TriggerList *current = qpropertyChangeTriggers;
359 if (!current->target) {
360 *prev = current->next;
361 QRecyclePool<TriggerList>::Delete(current);
363 }
else if (current->target == target && current->propertyIndex == propertyIndex) {
366 prev = ¤t->next;
367 current = current->next;
374void QQmlPropertyCapture::captureTranslation()
378 int const invalidIndex = -2;
379 if (expression->needsPropertyChangeTrigger(engine, invalidIndex)) {
380 auto trigger = expression->allocatePropertyChangeTrigger(engine, invalidIndex);
381 trigger->setSource(QQmlEnginePrivate::get(engine)->translationLanguage);
385void QQmlPropertyCapture::captureBindableProperty(
386 QObject *o,
const QMetaObject *metaObjectForBindable,
int c)
390 if (!expression->mustCaptureBindableProperty())
393 if (expression->needsPropertyChangeTrigger(o, c)) {
394 auto trigger = expression->allocatePropertyChangeTrigger(o, c);
395 QUntypedBindable bindable;
396 void *argv[] = { &bindable };
397 metaObjectForBindable->metacall(o, QMetaObject::BindableProperty, c, argv);
398 bindable.observe(trigger);
402void QQmlPropertyCapture::captureNonBindableProperty(QObject *o,
int n,
int c,
bool doNotify)
406 errorString =
new QStringList;
407 QString preamble = QLatin1String(
"QQmlExpression: Expression ") +
408 expression->expressionIdentifier() +
409 QLatin1String(
" depends on non-bindable properties:");
410 errorString->append(preamble);
413 const QMetaProperty metaProp = o->metaObject()->property(c);
414 QString error = QLatin1String(
" ") +
415 QString::fromUtf8(o->metaObject()->className()) +
416 QLatin1String(
"::") +
417 QString::fromUtf8(metaProp.name());
418 errorString->append(error);
422 while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
423 guards.takeFirst()->Delete();
425 QQmlJavaScriptExpressionGuard *g =
nullptr;
426 if (!guards.isEmpty()) {
427 g = guards.takeFirst();
429 Q_ASSERT(g->isConnected(o, n));
431 g = QQmlJavaScriptExpressionGuard::New(expression, engine);
432 g->connect(o, n, engine, doNotify);
435 expression->activeGuards.prepend(g);
439QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine)
const
444 return m_error->error();
449QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
452 m_error =
new QQmlDelayedError;
453 return m_error.data();
457QQmlJavaScriptExpression::evalFunction(
458 const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scopeObject,
459 const QString &code,
const QString &filename, quint16 line)
461 QQmlEngine *engine = ctxt->engine();
462 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
464 QV4::ExecutionEngine *v4 = engine->handle();
465 QV4::Scope scope(v4);
467 QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, scopeObject));
468 QV4::Script script(v4, qmlContext,
true, code, filename, line);
469 QV4::ScopedValue result(scope);
471 if (!v4->hasException)
472 result = script.run();
473 if (v4->hasException) {
474 QQmlError error = v4->catchExceptionAsQmlError();
475 if (error.description().isEmpty())
476 error.setDescription(QLatin1String(
"Exception occurred during function evaluation"));
477 if (error.line() == -1)
479 if (error.url().isEmpty())
480 error.setUrl(QUrl::fromLocalFile(filename));
481 error.setObject(scopeObject);
483 return QV4::Encode::undefined();
485 return result->asReturnedValue();
488void QQmlJavaScriptExpression::createQmlBinding(
489 const QQmlRefPointer<QQmlContextData> &ctxt, QObject *qmlScope,
const QString &code,
490 const QString &filename, quint16 line)
492 QQmlEngine *engine = ctxt->engine();
493 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
495 QV4::ExecutionEngine *v4 = engine->handle();
496 QV4::Scope scope(v4);
498 QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, qmlScope));
499 QV4::Script script(v4, qmlContext,
true, code, filename, line);
501 if (v4->hasException) {
502 QQmlDelayedError *error = delayedError();
503 error->catchJavaScriptException(v4);
504 error->setErrorObject(qmlScope);
505 if (!error->addError(ep))
506 ep->warning(error->error());
509 setupFunction(qmlContext, script.function());
512void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f)
514 if (!qmlContext || !f)
516 m_qmlScope.set(qmlContext->engine(), *qmlContext);
518 m_compilationUnit.reset(m_v4Function->executableCompilationUnit());
521void QQmlJavaScriptExpression::setCompilationUnit(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
523 m_compilationUnit = compilationUnit;
526void QPropertyChangeTrigger::trigger(QPropertyObserver *observer, QUntypedPropertyData *) {
527 auto This =
static_cast<QPropertyChangeTrigger *>(observer);
528 This->m_expression->expressionChanged();
531QMetaProperty QPropertyChangeTrigger::property()
const
535 auto const mo = target->metaObject();
538 return mo->property(propertyIndex);
541QPropertyChangeTrigger *QQmlJavaScriptExpression::allocatePropertyChangeTrigger(QObject *target,
int propertyIndex)
543 auto trigger = QQmlEnginePrivate::get(engine())->qPropertyTriggerPool.New(
this );
544 trigger->target = target;
545 trigger->propertyIndex = propertyIndex;
546 auto oldHead = qpropertyChangeTriggers;
547 trigger->next = oldHead;
548 qpropertyChangeTriggers = trigger;
552void QQmlJavaScriptExpression::clearActiveGuards()
554 while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst())
560 QQmlJavaScriptExpression *expression =
561 static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression;
563 expression->expressionChanged();