Example #1
0
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;
            }
        }
    }
}
Example #2
0
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;
}
Example #3
0
/*!
  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;
}
Example #4
0
/*!
    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);
    }
}
Example #5
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));
}
Example #6
0
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));
}
Example #7
0
/*!
    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);
}