/*! If \a script is a simple enumeration expression (eg. Text.AlignLeft), returns the integer equivalent (eg. 1), and sets \a ok to true. Otherwise sets \a ok to false. A valid \a ok must be provided, or the function will assert. */ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const { Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer"); *ok = false; int dot = script.indexOf('.'); if (dot == -1) return -1; QString scope = QString::fromUtf8(script.left(dot)); QByteArray enumValue = script.mid(dot+1); if (scope != QLatin1String("Qt")) { if (imports.isNull()) return -1; QQmlType *type = 0; if (imports.isT1()) { imports.asT1()->resolveType(scope, &type, 0, 0, 0); } else { QQmlTypeNameCache::Result result = imports.asT2()->query(scope); if (result.isValid()) type = result.type; } return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; } const QMetaObject *mo = StaticQtMetaObject::get(); int i = mo->enumeratorCount(); while (i--) { int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok); if (*ok) return v; } return -1; }
ReturnedValue QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlTypeWrapper>()); QV4::ExecutionEngine *v4 = static_cast<QmlTypeWrapper *>(m)->engine(); QV4::Scope scope(v4); Scoped<QmlTypeWrapper> w(scope, static_cast<QmlTypeWrapper *>(m)); if (hasProperty) *hasProperty = true; QQmlContextData *context = v4->v8Engine->callingContext(); QObject *object = w->d()->object; if (w->d()->type) { QQmlType *type = w->d()->type; // singleton types are handled differently to other types. if (type->isSingleton()) { QQmlEngine *e = v4->qmlEngine(); QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); siinfo->init(e); QObject *qobjectSingleton = siinfo->qobjectApi(e); if (qobjectSingleton) { // check for enum value if (name->startsWithUpper()) { if (w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums) { // ### Optimize QByteArray enumName = name->toQString().toUtf8(); const QMetaObject *metaObject = qobjectSingleton->metaObject(); for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { QMetaEnum e = metaObject->enumerator(ii); bool ok; int value = e.keyToValue(enumName.constData(), &ok); if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); } } } // check for property. return QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); } else if (!siinfo->scriptApi(e).isUndefined()) { // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); if (!!o) return o->get(name); } // Fall through to base implementation } else { if (name->startsWithUpper()) { bool ok = false; int value = type->enumValue(name, &ok); if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); // Fall through to base implementation } else if (w->d()->object) { QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object); if (ao) return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); // Fall through to base implementation } // Fall through to base implementation } // Fall through to base implementation } else if (w->d()->typeNamespace) { Q_ASSERT(w->d()->importNamespace); QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace); if (r.isValid()) { if (r.type) { return create(scope.engine, object, r.type, w->d()->mode); } else if (r.scriptIndex != -1) { QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); return scripts->getIndexed(r.scriptIndex); } else if (r.importNamespace) { return create(scope.engine, object, context->imports, r.importNamespace); } return QV4::Encode::undefined(); } // Fall through to base implementation } else { Q_ASSERT(!"Unreachable"); } if (hasProperty) *hasProperty = false; return Object::get(m, name, hasProperty); }
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>(); }
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(); }