Ejemplo n.º 1
0
static v8::Handle<v8::Value> qmlsqldatabase_changeVersion(const v8::Arguments& args)
{
    if (args.Length() < 2)
        return v8::Undefined();

    QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
    if (!r || r->type != QV8SqlDatabaseResource::Database)
        V8THROW_REFERENCE("Not a SQLDatabase object");

    QV8Engine *engine = r->engine;

    QSqlDatabase db = r->database;
    QString from_version = engine->toString(args[0]);
    QString to_version = engine->toString(args[1]);
    v8::Handle<v8::Value> callback = args[2];

    if (from_version != r->version)
        V8THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version));

    v8::Local<v8::Object> instance = databaseData(engine)->queryConstructor->NewInstance();
    QV8SqlDatabaseResource *r2 = new QV8SqlDatabaseResource(engine);
    r2->type = QV8SqlDatabaseResource::Query;
    r2->database = db;
    r2->version = r->version;
    r2->inTransaction = true;
    instance->SetExternalResource(r2);

    bool ok = true;
    if (callback->IsFunction()) {
        ok = false;
        db.transaction();

        v8::TryCatch tc;
        v8::Handle<v8::Value> callbackArgs[] = { instance };
        v8::Handle<v8::Function>::Cast(callback)->Call(engine->global(), 1, callbackArgs);

        if (tc.HasCaught()) {
            db.rollback();
            tc.ReThrow();
            return v8::Handle<v8::Value>();
        } else if (!db.commit()) {
            db.rollback();
            V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed"));
        } else {
            ok = true;
        }
    }

    r2->inTransaction = false;

    if (ok) {
        r2->version = to_version;
#ifndef QT_NO_SETTINGS
        QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat);
        ini.setValue(QLatin1String("Version"), to_version);
#endif
    }

    return v8::Undefined();
}
v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property, 
                                                v8::Local<v8::Value> value,
                                                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>();

    // See QV8ContextWrapper::Getter for resolution order
    
    QV8Engine *engine = resource->engine;
    QObject *scopeObject = resource->getScopeObject();

    QHashedV8String propertystring(property);

    QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();

    while (context) {
        // Search context properties
        if (context->propertyNames && -1 != context->propertyNames->value(propertystring))
            return value;

        // Search scope object
        if (scopeObject && 
            qobjectWrapper->setProperty(scopeObject, propertystring, context, value, QV8QObjectWrapper::CheckRevision))
            return value;
        scopeObject = 0;

        // Search context object
        if (context->contextObject &&
            qobjectWrapper->setProperty(context->contextObject, propertystring, context, value,
                                        QV8QObjectWrapper::CheckRevision))
            return value;

        context = context->parent;
    }

    expressionContext->unresolvedNames = true;

    if (!resource->readOnly) {
        return v8::Handle<v8::Value>();
    } else {
        QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) + 
                        QLatin1Char('"');
        v8::ThrowException(v8::Exception::Error(engine->toString(error)));
        return v8::Undefined();
    }
}
v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> property, 
                                                    v8::Local<v8::Value>,
                                                    const v8::AccessorInfo &info)
{
    QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());

    QV8Engine *engine = resource->engine;

    if (!resource->readOnly) {
        return v8::Handle<v8::Value>();
    } else {
        QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) + 
                        QLatin1Char('"');
        v8::ThrowException(v8::Exception::Error(engine->toString(error)));
        return v8::Handle<v8::Value>();
    }
}
Ejemplo n.º 4
0
static v8::Handle<v8::Value> qmlsqldatabase_transaction_shared(const v8::Arguments& args, bool readOnly)
{
    QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
    if (!r || r->type != QV8SqlDatabaseResource::Database)
        V8THROW_REFERENCE("Not a SQLDatabase object");

    QV8Engine *engine = r->engine;

    if (args.Length() == 0 || !args[0]->IsFunction())
        V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("transaction: missing callback"));

    QSqlDatabase db = r->database;
    v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(args[0]);

    v8::Local<v8::Object> instance = databaseData(engine)->queryConstructor->NewInstance();
    QV8SqlDatabaseResource *q = new QV8SqlDatabaseResource(engine);
    q->type = QV8SqlDatabaseResource::Query;
    q->database = db;
    q->readonly = readOnly;
    q->inTransaction = true;
    instance->SetExternalResource(q);

    db.transaction();
    v8::TryCatch tc;
    v8::Handle<v8::Value> callbackArgs[] = { instance };
    callback->Call(engine->global(), 1, callbackArgs);

    q->inTransaction = false;

    if (tc.HasCaught()) {
        db.rollback();
        tc.ReThrow();
        return v8::Handle<v8::Value>();
    } else if (!db.commit()) {
        db.rollback();
    }

    return v8::Undefined();
}
// Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value().
// Changes made here may need to be made there and vice versa.
void QQmlBoundSignalExpression::evaluate(void **a)
{
    Q_ASSERT (context() && engine());

    if (invalidParameterName())
        return;

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
    QV4::Scope scope(ep->v4engine());

    ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
    {
        if (!expressionFunctionValid()) {
            Q_ASSERT(!m_extra.isNull());
            QString expression;

            // Add some leading whitespace to account for the binding's column offset.
            // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
            expression.fill(QChar(QChar::Space), qMax(m_extra->m_sourceLocation.column, (quint16)2) - 2);
            expression += QStringLiteral("(function ");
            expression += m_extra->m_handlerName;
            expression += QLatin1Char('(');

            if (m_extra->m_parameterString.isEmpty()) {
                QString error;
                //TODO: look at using the property cache here (as in the compiler)
                //      for further optimization
                QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
                expression += QQmlPropertyCache::signalParameterStringForJS(engine(), signal.parameterNames(), &error);

                if (!error.isEmpty()) {
                    qmlInfo(scopeObject()) << error;
                    setInvalidParameterName(true);
                    ep->dereferenceScarceResources();
                    return;
                }
            } else
                expression += m_extra->m_parameterString;

            expression += QStringLiteral(") { ");
            expression += m_extra->m_expression;
            expression += QStringLiteral(" })");

            m_extra->m_expression.clear();
            m_extra->m_handlerName.clear();
            m_extra->m_parameterString.clear();

            m_v8function = evalFunction(context(), scopeObject(), expression,
                                        m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope);

            if (m_v8function.isNullOrUndefined()) {
                ep->dereferenceScarceResources();
                return; // could not evaluate function.  Not valid.
            }

            setExpressionFunctionValid(true);
        }

        QV8Engine *engine = ep->v8engine();
        QVarLengthArray<int, 9> dummy;
        //TODO: lookup via signal index rather than method index as an optimization
        int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
        int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0);
        int argCount = argsTypes ? *argsTypes : 0;

        QV4::ScopedValue f(scope, m_v8function.value());
        QV4::ScopedCallData callData(scope, argCount);
        for (int ii = 0; ii < argCount; ++ii) {
            int type = argsTypes[ii + 1];
            //### ideally we would use metaTypeToJS, however it currently gives different results
            //    for several cases (such as QVariant type and QObject-derived types)
            //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
            if (type == QMetaType::QVariant) {
                callData->args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1]));
            } else if (type == QMetaType::Int) {
                //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
                callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
            } else if (type == qMetaTypeId<QQmlV4Handle>()) {
                callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]);
            } else if (ep->isQObject(type)) {
                if (!*reinterpret_cast<void* const *>(a[ii + 1]))
                    callData->args[ii] = QV4::Primitive::nullValue();
                else
                    callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1]));
            } else {
                callData->args[ii] = engine->fromVariant(QVariant(type, a[ii + 1]));
            }
        }

        QQmlJavaScriptExpression::evaluate(context(), f, callData, 0);
    }
    ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
/*!
    \internal
    convert \a value to \a type, store the result in \a ptr
*/
bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
{
    QJSValuePrivate *vp = QJSValuePrivate::get(value);
    QV8Engine *engine = vp->engine ? vp->engine->v8Engine : 0;
    if (engine) {
        QV4::Scope scope(engine->m_v4Engine);
        QV4::ScopedValue v(scope, vp->getValue(engine->m_v4Engine));
        return engine->metaTypeFromJS(v, type, ptr);
    } else if (vp->value.isEmpty()) {
        // have a string based value without engine. Do conversion manually
        if (type == QMetaType::Bool) {
            *reinterpret_cast<bool*>(ptr) = vp->string.length() != 0;
            return true;
        }
        if (type == QMetaType::QString) {
            *reinterpret_cast<QString*>(ptr) = vp->string;
            return true;
        }
        double d = QV4::RuntimeHelpers::stringToNumber(vp->string);
        switch (type) {
            case QMetaType::Int:
                *reinterpret_cast<int*>(ptr) = QV4::Primitive::toInt32(d);
                return true;
            case QMetaType::UInt:
                *reinterpret_cast<uint*>(ptr) = QV4::Primitive::toUInt32(d);
                return true;
            case QMetaType::LongLong:
                *reinterpret_cast<qlonglong*>(ptr) = QV4::Primitive::toInteger(d);
                return true;
            case QMetaType::ULongLong:
                *reinterpret_cast<qulonglong*>(ptr) = QV4::Primitive::toInteger(d);
                return true;
            case QMetaType::Double:
                *reinterpret_cast<double*>(ptr) = d;
                return true;
            case QMetaType::Float:
                *reinterpret_cast<float*>(ptr) = d;
                return true;
            case QMetaType::Short:
                *reinterpret_cast<short*>(ptr) = QV4::Primitive::toInt32(d);
                return true;
            case QMetaType::UShort:
                *reinterpret_cast<unsigned short*>(ptr) = QV4::Primitive::toUInt32(d);
                return true;
            case QMetaType::Char:
                *reinterpret_cast<char*>(ptr) = QV4::Primitive::toInt32(d);
                return true;
            case QMetaType::UChar:
                *reinterpret_cast<unsigned char*>(ptr) = QV4::Primitive::toUInt32(d);
                return true;
            case QMetaType::QChar:
                *reinterpret_cast<QChar*>(ptr) = QV4::Primitive::toUInt32(d);
                return true;
            default:
                return false;
        }
    } else {
        switch (type) {
            case QMetaType::Bool:
                *reinterpret_cast<bool*>(ptr) = vp->value.toBoolean();
                return true;
            case QMetaType::Int:
                *reinterpret_cast<int*>(ptr) = vp->value.toInt32();
                return true;
            case QMetaType::UInt:
                *reinterpret_cast<uint*>(ptr) = vp->value.toUInt32();
                return true;
            case QMetaType::LongLong:
                *reinterpret_cast<qlonglong*>(ptr) = vp->value.toInteger();
                return true;
            case QMetaType::ULongLong:
                *reinterpret_cast<qulonglong*>(ptr) = vp->value.toInteger();
                return true;
            case QMetaType::Double:
                *reinterpret_cast<double*>(ptr) = vp->value.toNumber();
                return true;
            case QMetaType::QString:
                *reinterpret_cast<QString*>(ptr) = value.toString();
                return true;
            case QMetaType::Float:
                *reinterpret_cast<float*>(ptr) = vp->value.toNumber();
                return true;
            case QMetaType::Short:
                *reinterpret_cast<short*>(ptr) = vp->value.toInt32();
                return true;
            case QMetaType::UShort:
                *reinterpret_cast<unsigned short*>(ptr) = vp->value.toUInt16();
                return true;
            case QMetaType::Char:
                *reinterpret_cast<char*>(ptr) = vp->value.toInt32();
                return true;
            case QMetaType::UChar:
                *reinterpret_cast<unsigned char*>(ptr) = vp->value.toUInt16();
                return true;
            case QMetaType::QChar:
                *reinterpret_cast<QChar*>(ptr) = vp->value.toUInt16();
                return true;
            default:
                return false;
        }
    }
}
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>();
}
Ejemplo n.º 8
0
void QQuickLocalStorage::openDatabaseSync(QQmlV8Function *args)
{
#ifndef QT_NO_SETTINGS
    QV8Engine *engine = args->engine();
    if (engine->engine()->offlineStoragePath().isEmpty())
        V8THROW_SQL_VOID(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));

    qmlsqldatabase_initDatabasesPath(engine);

    QSqlDatabase database;

    QString dbname = engine->toString((*args)[0]);
    QString dbversion = engine->toString((*args)[1]);
    QString dbdescription = engine->toString((*args)[2]);
    int dbestimatedsize = (*args)[3]->Int32Value();
    v8::Handle<v8::Value> dbcreationCallback = (*args)[4];

    QCryptographicHash md5(QCryptographicHash::Md5);
    md5.addData(dbname.toUtf8());
    QString dbid(QLatin1String(md5.result().toHex()));

    QString basename = qmlsqldatabase_databaseFile(dbid, engine);
    bool created = false;
    QString version = dbversion;

    {
        QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);

        if (QSqlDatabase::connectionNames().contains(dbid)) {
            database = QSqlDatabase::database(dbid);
            version = ini.value(QLatin1String("Version")).toString();
            if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
                V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch"));
        } else {
            created = !QFile::exists(basename+QLatin1String(".sqlite"));
            database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
            if (created) {
                ini.setValue(QLatin1String("Name"), dbname);
                if (dbcreationCallback->IsFunction())
                    version = QString();
                ini.setValue(QLatin1String("Version"), version);
                ini.setValue(QLatin1String("Description"), dbdescription);
                ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize);
                ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE"));
            } else {
                if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
                    // Incompatible
                    V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch"));
                }
                version = ini.value(QLatin1String("Version")).toString();
            }
            database.setDatabaseName(basename+QLatin1String(".sqlite"));
        }
        if (!database.isOpen())
            database.open();
    }

    v8::Local<v8::Object> instance = databaseData(engine)->constructor->NewInstance();

    QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine);
    r->database = database;
    r->version = version;
    instance->SetExternalResource(r);

    if (created && dbcreationCallback->IsFunction()) {
        v8::TryCatch tc;
        v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(dbcreationCallback);
        v8::Handle<v8::Value> args[] = { instance };
        callback->Call(engine->global(), 1, args);
        if (tc.HasCaught()) {
            tc.ReThrow();
            return;
        }
    }

    args->returnValue(instance);
#endif // QT_NO_SETTINGS
}
Ejemplo n.º 9
0
static v8::Handle<v8::Value> qmlsqldatabase_executeSql(const v8::Arguments& args)
{
    QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
    if (!r || r->type != QV8SqlDatabaseResource::Query)
        V8THROW_REFERENCE("Not a SQLDatabase::Query object");

    QV8Engine *engine = r->engine;

    if (!r->inTransaction)
        V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr("executeSql called outside transaction()"));

    QSqlDatabase db = r->database;

    QString sql = engine->toString(args[0]);

    if (r->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
        V8THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction"));
    }

    QSqlQuery query(db);
    bool err = false;

    v8::Handle<v8::Value> result = v8::Undefined();

    if (query.prepare(sql)) {
        if (args.Length() > 1) {
            v8::Local<v8::Value> values = args[1];
            if (values->IsArray()) {
                v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(values);
                uint32_t size = array->Length();
                for (uint32_t ii = 0; ii < size; ++ii)
                    query.bindValue(ii, engine->toVariant(array->Get(ii), -1));
            } else if (values->IsObject() && !values->ToObject()->GetExternalResource()) {
                v8::Local<v8::Object> object = values->ToObject();
                v8::Local<v8::Array> names = object->GetPropertyNames();
                uint32_t size = names->Length();
                for (uint32_t ii = 0; ii < size; ++ii)
                    query.bindValue(engine->toString(names->Get(ii)),
                                    engine->toVariant(object->Get(names->Get(ii)), -1));
            } else {
                query.bindValue(0, engine->toVariant(values, -1));
            }
        }
        if (query.exec()) {
            v8::Handle<v8::Object> rows = databaseData(engine)->rowsConstructor->NewInstance();
            QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine);
            r->type = QV8SqlDatabaseResource::Rows;
            r->database = db;
            r->query = query;
            rows->SetExternalResource(r);

            v8::Local<v8::Object> resultObject = v8::Object::New();
            result = resultObject;
            // XXX optimize
            resultObject->Set(v8::String::New("rowsAffected"), v8::Integer::New(query.numRowsAffected()));
            resultObject->Set(v8::String::New("insertId"), engine->toString(query.lastInsertId().toString()));
            resultObject->Set(v8::String::New("rows"), rows);
        } else {
            err = true;
        }
    } else {
        err = true;
    }
    if (err)
        V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text());

    return result;
}
Ejemplo n.º 10
0
// Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value().
// Changes made here may need to be made there and vice versa.
void QQmlBoundSignalExpression::evaluate(void **a)
{
    Q_ASSERT (context() && engine());

    if (m_invalidParameterName)
        return;

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());

    ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
    {
        v8::HandleScope handle_scope;
        v8::Context::Scope context_scope(ep->v8engine()->context());
        if (!m_expressionFunctionValid) {

            //TODO: look at using the property cache here (as in the compiler)
            //      for further optimization
            QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
            QQmlRewrite::RewriteSignalHandler rewriter;

            QString expression;
            bool ok = true;

            if (m_expressionFunctionRewritten) {
                expression = QString::fromUtf8(m_expressionUtf8);

                //if we need parameters, and the rewrite doesn't include them,
                //create and insert the parameter string now
                if (m_parameterCountForJS == -1 && signal.parameterCount()) {
                    const QString &parameters = rewriter.createParameterString(signal.parameterNames(),
                                                ep->v8engine()->illegalNames());
                    int index = expression.indexOf(QLatin1Char('('), 1);
                    Q_ASSERT(index > -1);
                    expression.insert(index + 1, parameters);

                    setParameterCountForJS(rewriter.parameterCountForJS());
                }

                m_expressionUtf8.clear();
            } else {
                //expression is still in its original form, so perform a full rewrite
                expression = rewriter(m_expression, QString()/*no name hint available*/, &ok,
                                      signal.parameterNames(),
                                      ep->v8engine()->illegalNames());
                setParameterCountForJS(rewriter.parameterCountForJS());
                m_expression.clear();
            }

            if (rewriter.hasParameterError()) {
                qmlInfo(scopeObject()) << rewriter.parameterError();
                m_invalidParameterName = true;
                ep->dereferenceScarceResources();
                return;
            }

            if (ok) {
                m_v8function = evalFunction(context(), scopeObject(), expression,
                                            m_fileName, m_line, &m_v8qmlscope);
            }

            if (m_v8function.IsEmpty() || m_v8function->IsNull()) {
                ep->dereferenceScarceResources();
                return; // could not evaluate function.  Not valid.
            }

            setUseSharedContext(false);
            m_expressionFunctionValid = true;
        }

        if (!hasParameterInfo()) {
            QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0);
        } else {
            QV8Engine *engine = ep->v8engine();
            QVarLengthArray<int, 9> dummy;
            //TODO: lookup via signal index rather than method index as an optimization
            int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
            int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0);
            int argCount = argsTypes ? m_parameterCountForJS : 0;

            QVarLengthArray<v8::Handle<v8::Value>, 9> args(argCount);

            for (int ii = 0; ii < argCount; ++ii) {
                int type = argsTypes[ii + 1];
                //### ideally we would use metaTypeToJS, however it currently gives different results
                //    for several cases (such as QVariant type and QObject-derived types)
                //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
                if (type == QMetaType::QVariant) {
                    args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1]));
                } else if (type == QMetaType::Int) {
                    //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
                    args[ii] = v8::Integer::New(*reinterpret_cast<const int*>(a[ii + 1]));
                } else if (type == qMetaTypeId<QQmlV8Handle>()) {
                    args[ii] = reinterpret_cast<QQmlV8Handle *>(a[ii + 1])->toHandle();
                } else if (ep->isQObject(type)) {
                    if (!*reinterpret_cast<void* const *>(a[ii + 1]))
                        args[ii] = v8::Null();
                    else
                        args[ii] = engine->newQObject(*reinterpret_cast<QObject* const *>(a[ii + 1]));
                } else {
                    args[ii] = engine->fromVariant(QVariant(type, a[ii + 1]));
                }
            }

            QQmlJavaScriptExpression::evaluate(context(), m_v8function, argCount, args.data(), 0);
        }
    }
    ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
Ejemplo n.º 11
0
/*
    Documented in qv8engine.cpp
*/
v8::Handle<v8::Value> QV8Include::include(const v8::Arguments &args)
{
    if (args.Length() == 0)
        return v8::Undefined();

    QV8Engine *engine = V8ENGINE();
    QDeclarativeContextData *context = engine->callingContext();

    if (!context || !context->isJSContext) 
        V8THROW_ERROR("Qt.include(): Can only be called from JavaScript files");

    QUrl url(context->resolvedUrl(QUrl(engine->toString(args[0]->ToString()))));
    
    v8::Local<v8::Function> callbackFunction;
    if (args.Length() >= 2 && args[1]->IsFunction())
        callbackFunction = v8::Local<v8::Function>::Cast(args[1]);

    QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);

    v8::Local<v8::Object> result;

    if (localFile.isEmpty()) {

        QV8Include *i = new QV8Include(url, engine, context, 
                                       v8::Context::GetCallingQmlGlobal(), 
                                       callbackFunction);
        result = v8::Local<v8::Object>::New(i->result());

    } else { 

        QFile f(localFile);

        if (f.open(QIODevice::ReadOnly)) {
            QByteArray data = f.readAll();
            QString code = QString::fromUtf8(data);
            QDeclarativeScriptParser::extractPragmas(code);

            QDeclarativeContextData *importContext = new QDeclarativeContextData;
            importContext->isInternal = true;
            importContext->isJSContext = true;
            importContext->url = url;
            importContext->setParent(context, true);

            v8::TryCatch try_catch;

            v8::Local<v8::Script> script = engine->qmlModeCompile(code, url.toString());

            if (!try_catch.HasCaught()) {
                v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
                engine->contextWrapper()->addSubContext(qmlglobal, script, importContext);
                script->Run(qmlglobal);
            }

            if (try_catch.HasCaught()) {
                result = resultValue(Exception);
                result->Set(v8::String::New("exception"), try_catch.Exception());
            } else {
                result = resultValue(Ok);
            }

        } else {
            result = resultValue(NetworkError);
        }

        callback(engine, callbackFunction, result);
    }

    if (result.IsEmpty())
        return v8::Undefined();
    else 
        return result;
}