void QQmlContextData::emitDestruction() { if (!hasEmittedDestruction) { hasEmittedDestruction = true; // Emit the destruction signal - must be emitted before invalidate so that the // context is still valid if bindings or resultant expression evaluation requires it if (engine) { while (componentAttached) { QQmlComponentAttached *a = componentAttached; componentAttached = a->next; if (componentAttached) componentAttached->prev = &componentAttached; a->next = 0; a->prev = 0; emit a->destruction(); } QQmlContextData * child = childContexts; while (child) { child->emitDestruction(); child = child->nextChild; } } } }
QUrl QQmlContextData::resolvedUrl(const QUrl &src) { QQmlContextData *ctxt = this; QUrl resolved; if (src.isRelative() && !src.isEmpty()) { if (ctxt) { while(ctxt) { if (ctxt->url().isValid()) break; else ctxt = ctxt->parent; } if (ctxt) resolved = ctxt->url().resolved(src); else if (engine) resolved = engine->baseUrl().resolved(src); } } else { resolved = src; } if (resolved.isEmpty()) //relative but no ctxt return resolved; if (engine && engine->urlInterceptor()) resolved = engine->urlInterceptor()->intercept(resolved, QQmlAbstractUrlInterceptor::UrlString); return resolved; }
/*! Returns the value of the \a name property for this context as a QVariant. */ QVariant QQmlContext::contextProperty(const QString &name) const { Q_D(const QQmlContext); QVariant value; int idx = -1; QQmlContextData *data = d->data; const QV4::IdentifierHash<int> &properties = data->propertyNames(); if (properties.count()) idx = properties.value(name); if (idx == -1) { if (data->contextObject) { QObject *obj = data->contextObject; QQmlPropertyData local; QQmlPropertyData *property = QQmlPropertyCache::property(data->engine, obj, name, data, local); if (property) value = obj->metaObject()->property(property->coreIndex()).read(obj); } if (!value.isValid() && parentContext()) value = parentContext()->contextProperty(name); } else { if (idx >= d->propertyValues.count()) value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data()); else value = d->propertyValues[idx]; } return value; }
/*! Set the \a value of the \a name property on this context. QQmlContext does \b not take ownership of \a value. */ void QQmlContext::setContextProperty(const QString &name, QObject *value) { Q_D(QQmlContext); if (d->notifyIndex == -1) d->notifyIndex = QMetaObjectPrivate::absoluteSignalCount(&QQmlContext::staticMetaObject); QQmlContextData *data = d->data; if (data->isInternal) { qWarning("QQmlContext: Cannot set property on internal context."); return; } if (!isValid()) { qWarning("QQmlContext: Cannot set property on invalid context."); return; } QV4::IdentifierHash<int> &properties = data->detachedPropertyNames(); int idx = properties.value(name); if (idx == -1) { properties.add(name, data->idValueCount + d->propertyValues.count()); d->propertyValues.append(QVariant::fromValue(value)); data->refreshExpressions(); } else { d->propertyValues[idx] = QVariant::fromValue(value); QMetaObject::activate(this, d->notifyIndex, idx, 0); } }
QUrl QQuickLoaderPrivate::resolveSourceUrl(QQmlV8Function *args) { QV8Engine *v8engine = args->engine(); QString arg = v8engine->toString((*args)[0]->ToString()); if (arg.isEmpty()) return QUrl(); QQmlContextData *context = args->context(); Q_ASSERT(context); return context->resolvedUrl(QUrl(arg)); }
QUrl QQuickLoaderPrivate::resolveSourceUrl(QQmlV4Function *args) { QV4::Scope scope(args->v4engine()); QV4::ScopedValue v(scope, (*args)[0]); QString arg = v->toQString(); if (arg.isEmpty()) return QUrl(); QQmlContextData *context = args->context(); Q_ASSERT(context); return context->resolvedUrl(QUrl(arg)); }
/*! Set the context \a object. */ void QQmlContext::setContextObject(QObject *object) { Q_D(QQmlContext); QQmlContextData *data = d->data; if (data->isInternal) { qWarning("QQmlContext: Cannot set context object for internal context."); return; } if (!isValid()) { qWarning("QQmlContext: Cannot set context object on invalid context."); return; } data->contextObject = object; data->refreshExpressions(); }
v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property, const v8::AccessorInfo &info) { QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This()); // Its possible we could delay the calculation of the "actual" context (in the case // of sub contexts) until it is definately needed. QQmlContextData *context = resource->getContext(); QQmlContextData *expressionContext = context; if (!context) return v8::Undefined(); if (v8::Context::GetCallingQmlGlobal() != info.This()) return v8::Handle<v8::Value>(); // Search type (attached property/enum/imported scripts) names // while (context) { // Search context properties // Search scope object // Search context object // context = context->parent // } QV8Engine *engine = resource->engine; QObject *scopeObject = resource->getScopeObject(); QHashedV8String propertystring(property); if (context->imports && QV8Engine::startsWithUpper(property)) { // Search for attached properties, enums and imported scripts QQmlTypeNameCache::Result r = context->imports->query(propertystring); if (r.isValid()) { if (r.scriptIndex != -1) { int index = r.scriptIndex; if (index < context->importedScripts.count()) return context->importedScripts.at(index); else return v8::Undefined(); } else if (r.type) { return engine->typeWrapper()->newObject(scopeObject, r.type); } else if (r.importNamespace) { return engine->typeWrapper()->newObject(scopeObject, context->imports, r.importNamespace); } Q_ASSERT(!"Unreachable"); } // Fall through } QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->engine()); QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper(); while (context) { // Search context properties if (context->propertyNames) { int propertyIdx = context->propertyNames->value(propertystring); if (propertyIdx != -1) { if (propertyIdx < context->idValueCount) { ep->captureProperty(&context->idValues[propertyIdx].bindings); return engine->newQObject(context->idValues[propertyIdx]); } else { QQmlContextPrivate *cp = context->asQQmlContextPrivate(); ep->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); const QVariant &value = cp->propertyValues.at(propertyIdx); if (value.userType() == qMetaTypeId<QList<QObject*> >()) { QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), QQmlContextPrivate::context_count, QQmlContextPrivate::context_at); return engine->listWrapper()->newList(prop, qMetaTypeId<QQmlListProperty<QObject> >()); } else { return engine->fromVariant(cp->propertyValues.at(propertyIdx)); } } } } // Search scope object if (scopeObject) { v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, propertystring, context, QV8QObjectWrapper::CheckRevision); if (!result.IsEmpty()) return result; } scopeObject = 0; // Search context object if (context->contextObject) { v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, propertystring, context, QV8QObjectWrapper::CheckRevision); if (!result.IsEmpty()) return result; } context = context->parent; } expressionContext->unresolvedNames = true; // V8 will throw a ReferenceError if appropriate ("typeof" should not throw) return v8::Handle<v8::Value>(); }
/*! Returns the QQmlContext this expression is associated with, or 0 if there is no association or the QQmlContext has been destroyed. */ QQmlContext *QQmlExpression::context() const { Q_D(const QQmlExpression); QQmlContextData *data = d->context(); return data?data->asQQmlContext():0; }
ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlContextWrapper>()); const QmlContextWrapper *resource = static_cast<const QmlContextWrapper *>(m); QV4::ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); // In V8 the JS global object would come _before_ the QML global object, // so simulate that here. bool hasProp; QV4::ScopedValue result(scope, v4->globalObject->get(name, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = hasProp; return result->asReturnedValue(); } if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); if (v4->callingQmlContext() != resource->d()->context) return Object::get(m, name, hasProperty); result = Object::get(m, name, &hasProp); if (hasProp) { if (hasProperty) *hasProperty = hasProp; return result->asReturnedValue(); } // Its possible we could delay the calculation of the "actual" context (in the case // of sub contexts) until it is definately needed. QQmlContextData *context = resource->getContext(); QQmlContextData *expressionContext = context; if (!context) { if (hasProperty) *hasProperty = true; return result->asReturnedValue(); } // Search type (attached property/enum/imported scripts) names // while (context) { // Search context properties // Search scope object // Search context object // context = context->parent // } QObject *scopeObject = resource->getScopeObject(); if (context->imports && name->startsWithUpper()) { // Search for attached properties, enums and imported scripts QQmlTypeNameCache::Result r = context->imports->query(name); if (r.isValid()) { if (hasProperty) *hasProperty = true; if (r.scriptIndex != -1) { QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); return scripts->getIndexed(r.scriptIndex); } else if (r.type) { return QmlTypeWrapper::create(v4, scopeObject, r.type); } else if (r.importNamespace) { return QmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace); } Q_ASSERT(!"Unreachable"); } // Fall through } QQmlEnginePrivate *ep = QQmlEnginePrivate::get(v4->qmlEngine()); while (context) { // Search context properties const QV4::IdentifierHash<int> &properties = context->propertyNames(); if (properties.count()) { int propertyIdx = properties.value(name); if (propertyIdx != -1) { if (propertyIdx < context->idValueCount) { if (ep->propertyCapture) ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); if (hasProperty) *hasProperty = true; return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]); } else { QQmlContextPrivate *cp = context->asQQmlContextPrivate(); if (ep->propertyCapture) ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); const QVariant &value = cp->propertyValues.at(propertyIdx); if (hasProperty) *hasProperty = true; if (value.userType() == qMetaTypeId<QList<QObject*> >()) { QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), QQmlContextPrivate::context_count, QQmlContextPrivate::context_at); return QmlListWrapper::create(v4, prop, qMetaTypeId<QQmlListProperty<QObject> >()); } else { return scope.engine->fromVariant(cp->propertyValues.at(propertyIdx)); } } } } // Search scope object if (scopeObject) { bool hasProp = false; QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = true; return result->asReturnedValue(); } } scopeObject = 0; // Search context object if (context->contextObject) { bool hasProp = false; result = QV4::QObjectWrapper::getQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp); if (hasProp) { if (hasProperty) *hasProperty = true; return result->asReturnedValue(); } } context = context->parent; } expressionContext->unresolvedNames = true; return Encode::undefined(); }
void QmlContextWrapper::put(Managed *m, String *name, const Value &value) { Q_ASSERT(m->as<QmlContextWrapper>()); QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m); ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); if (scope.hasException()) return; QV4::Scoped<QmlContextWrapper> wrapper(scope, resource); uint member = wrapper->internalClass()->find(name); if (member < UINT_MAX) { wrapper->putValue(member, value); return; } if (wrapper->d()->isNullWrapper) { if (wrapper && wrapper->d()->readOnly) { QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); ScopedString e(scope, v4->newString(error)); v4->throwError(e); return; } Object::put(m, name, value); return; } // Its possible we could delay the calculation of the "actual" context (in the case // of sub contexts) until it is definately needed. QQmlContextData *context = wrapper->getContext(); QQmlContextData *expressionContext = context; if (!context) return; // See QV8ContextWrapper::Getter for resolution order QObject *scopeObject = wrapper->getScopeObject(); while (context) { const QV4::IdentifierHash<int> &properties = context->propertyNames(); // Search context properties if (properties.count() && properties.value(name) != -1) return; // Search scope object if (scopeObject && QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value)) return; scopeObject = 0; // Search context object if (context->contextObject && QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value)) return; context = context->parent; } expressionContext->unresolvedNames = true; if (wrapper->d()->readOnly) { QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); v4->throwError(error); return; } Object::put(m, name, value); }