209 QQmlEnginePrivate *ep;
213QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData,
bool *isUndefined)
215 QQmlEngine *qmlEngine = engine();
216 QV4::Function *v4Function = function();
217 if (!v4Function || !qmlEngine) {
220 return QV4::Encode::undefined();
225 QQmlJavaScriptExpressionCapture capture(
this, qmlEngine);
227 QV4::Scope scope(qmlEngine->handle());
229 if (QObject *thisObject = scopeObject()) {
230 callData->thisObject = QV4::QObjectWrapper::wrap(scope.engine, thisObject);
231 if (callData->thisObject.isNullOrUndefined())
232 callData->thisObject = scope.engine->globalObject;
234 callData->thisObject = scope.engine->globalObject;
237 Q_ASSERT(m_qmlScope.valueRef());
238 QV4::ScopedValue result(scope, v4Function->call(
239 &(callData->thisObject.asValue<QV4::Value>()),
240 callData->argValues<QV4::Value>(), callData->argc(),
241 static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef())));
243 if (capture.catchException(scope)) {
246 }
else if (isUndefined) {
247 *isUndefined = result->isUndefined();
250 return result->asReturnedValue();
253bool QQmlJavaScriptExpression::evaluate(
void **a,
const QMetaType *types,
int argc)
257 QQmlEngine *qmlEngine = engine();
264 QQmlJavaScriptExpressionCapture capture(
this, qmlEngine);
266 QV4::Scope scope(qmlEngine->handle());
268 Q_ASSERT(m_qmlScope.valueRef());
269 Q_ASSERT(function());
270 const bool resultIsDefined = function()->call(
271 scopeObject(), a, types, argc,
272 static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
274 return !capture.catchException(scope) && resultIsDefined;
277void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
279 if (watcher->wasDeleted())
282 Q_ASSERT(expression);
284 while (!guards.isEmpty() && !guards.first()->isConnected(n))
285 guards.takeFirst()->Delete();
287 QQmlJavaScriptExpressionGuard *g =
nullptr;
288 if (!guards.isEmpty()) {
289 g = guards.takeFirst();
291 Q_ASSERT(g->isConnected(n));
293 g = QQmlJavaScriptExpressionGuard::New(expression, engine);
297 expression->activeGuards.prepend(g);
301
302
303
304void QQmlPropertyCapture::captureProperty(QObject *o,
int c,
int n,
bool doNotify)
306 if (watcher->wasDeleted())
309 Q_ASSERT(expression);
314 const QQmlData *ddata = QQmlData::get(o,
false);
315 const QMetaObject *metaObjectForBindable =
nullptr;
316 if (
auto const propCache = (ddata ? ddata->propertyCache.data() :
nullptr)) {
317 Q_ASSERT(propCache->property(c));
318 if (propCache->property(c)->notifiesViaBindable())
319 metaObjectForBindable = propCache->metaObject();
321 const QMetaObject *m = o->metaObject();
322 if (m->property(c).isBindable())
323 metaObjectForBindable = m;
325 if (metaObjectForBindable) {
326 captureBindableProperty(o, metaObjectForBindable, c);
331 captureNonBindableProperty(o, n, c, doNotify);
334void QQmlPropertyCapture::captureProperty(
335 QObject *o,
const QQmlPropertyCache *propertyCache,
const QQmlPropertyData *propertyData,
338 if (watcher->wasDeleted())
341 Q_ASSERT(expression);
343 if (propertyData->notifiesViaBindable()) {
344 if (
const QMetaObject *metaObjectForBindable = propertyCache->metaObject()) {
345 captureBindableProperty(o, metaObjectForBindable, propertyData->coreIndex());
350 captureNonBindableProperty(o, propertyData->notifyIndex(), propertyData->coreIndex(), doNotify);
353bool QQmlJavaScriptExpression::needsPropertyChangeTrigger(QObject *target,
int propertyIndex)
355 TriggerList **prev = &qpropertyChangeTriggers;
356 TriggerList *current = qpropertyChangeTriggers;
358 if (!current->target) {
359 *prev = current->next;
360 QRecyclePool<TriggerList>::Delete(current);
362 }
else if (current->target == target && current->propertyIndex == propertyIndex) {
365 prev = ¤t->next;
366 current = current->next;
373void QQmlPropertyCapture::captureTranslation()
377 int const invalidIndex = -2;
378 if (expression->needsPropertyChangeTrigger(engine, invalidIndex)) {
379 auto trigger = expression->allocatePropertyChangeTrigger(engine, invalidIndex);
380 trigger->setSource(QQmlEnginePrivate::get(engine)->translationLanguage);
384void QQmlPropertyCapture::captureBindableProperty(
385 QObject *o,
const QMetaObject *metaObjectForBindable,
int c)
389 if (!expression->mustCaptureBindableProperty())
392 if (expression->needsPropertyChangeTrigger(o, c)) {
393 auto trigger = expression->allocatePropertyChangeTrigger(o, c);
394 QUntypedBindable bindable;
395 void *argv[] = { &bindable };
396 metaObjectForBindable->metacall(o, QMetaObject::BindableProperty, c, argv);
397 bindable.observe(trigger);
401void QQmlPropertyCapture::captureNonBindableProperty(QObject *o,
int n,
int c,
bool doNotify)
405 errorString =
new QStringList;
406 QString preamble = QLatin1String(
"QQmlExpression: Expression ") +
407 expression->expressionIdentifier() +
408 QLatin1String(
" depends on non-bindable properties:");
409 errorString->append(preamble);
412 const QMetaProperty metaProp = o->metaObject()->property(c);
413 QString error = QLatin1String(
" ") +
414 QString::fromUtf8(o->metaObject()->className()) +
415 QLatin1String(
"::") +
416 QString::fromUtf8(metaProp.name());
417 errorString->append(error);
421 while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
422 guards.takeFirst()->Delete();
424 QQmlJavaScriptExpressionGuard *g =
nullptr;
425 if (!guards.isEmpty()) {
426 g = guards.takeFirst();
428 Q_ASSERT(g->isConnected(o, n));
430 g = QQmlJavaScriptExpressionGuard::New(expression, engine);
431 g->connect(o, n, engine, doNotify);
434 expression->activeGuards.prepend(g);
438QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine)
const
443 return m_error->error();
448QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
451 m_error =
new QQmlDelayedError;
452 return m_error.data();
456QQmlJavaScriptExpression::evalFunction(
457 const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scopeObject,
458 const QString &code,
const QString &filename, quint16 line)
460 QQmlEngine *engine = ctxt->engine();
461 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
463 QV4::ExecutionEngine *v4 = engine->handle();
464 QV4::Scope scope(v4);
466 QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, scopeObject));
467 QV4::Script script(v4, qmlContext,
true, code, filename, line);
468 QV4::ScopedValue result(scope);
470 if (!v4->hasException)
471 result = script.run();
472 if (v4->hasException) {
473 QQmlError error = v4->catchExceptionAsQmlError();
474 if (error.description().isEmpty())
475 error.setDescription(QLatin1String(
"Exception occurred during function evaluation"));
476 if (error.line() == -1)
478 if (error.url().isEmpty())
479 error.setUrl(QUrl::fromLocalFile(filename));
480 error.setObject(scopeObject);
482 return QV4::Encode::undefined();
484 return result->asReturnedValue();
487void QQmlJavaScriptExpression::createQmlBinding(
488 const QQmlRefPointer<QQmlContextData> &ctxt, QObject *qmlScope,
const QString &code,
489 const QString &filename, quint16 line)
491 QQmlEngine *engine = ctxt->engine();
492 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
494 QV4::ExecutionEngine *v4 = engine->handle();
495 QV4::Scope scope(v4);
497 QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, qmlScope));
498 QV4::Script script(v4, qmlContext,
true, code, filename, line);
500 if (v4->hasException) {
501 QQmlDelayedError *error = delayedError();
502 error->catchJavaScriptException(v4);
503 error->setErrorObject(qmlScope);
504 if (!error->addError(ep))
505 ep->warning(error->error());
508 setupFunction(qmlContext, script.function());
511void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f)
513 if (!qmlContext || !f)
515 m_qmlScope.set(qmlContext->engine(), *qmlContext);
517 m_compilationUnit.reset(m_v4Function->executableCompilationUnit());
520void QQmlJavaScriptExpression::setCompilationUnit(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
522 m_compilationUnit = compilationUnit;
525void QPropertyChangeTrigger::trigger(QPropertyObserver *observer, QUntypedPropertyData *) {
526 auto This =
static_cast<QPropertyChangeTrigger *>(observer);
527 This->m_expression->expressionChanged();
530QMetaProperty QPropertyChangeTrigger::property()
const
534 auto const mo = target->metaObject();
537 return mo->property(propertyIndex);
540QPropertyChangeTrigger *QQmlJavaScriptExpression::allocatePropertyChangeTrigger(QObject *target,
int propertyIndex)
542 auto trigger = QQmlEnginePrivate::get(engine())->qPropertyTriggerPool.New(
this );
543 trigger->target = target;
544 trigger->propertyIndex = propertyIndex;
545 auto oldHead = qpropertyChangeTriggers;
546 trigger->next = oldHead;
547 qpropertyChangeTriggers = trigger;
551void QQmlJavaScriptExpression::clearActiveGuards()
553 while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst())
559 QQmlJavaScriptExpression *expression =
560 static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression;
562 expression->expressionChanged();