diff options
Diffstat (limited to 'src/shared/envjsnatives.cpp')
-rw-r--r-- | src/shared/envjsnatives.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/src/shared/envjsnatives.cpp b/src/shared/envjsnatives.cpp new file mode 100644 index 0000000..6508f20 --- /dev/null +++ b/src/shared/envjsnatives.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 or 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include <QtCore> +#include <QtScript> +#include <QtNetwork> + +// Exported API. +void initializeEnvjsNatives(QScriptEngine *); + +#define ENVJS_FUNCTIONS(V) \ + V(lineSource) \ + V(eval) \ + V(loadInlineScript) \ + V(loadLocalScript) \ + V(sync) \ + V(spawn) \ + V(sleep) \ + V(loadFrame) \ + V(unloadFrame) \ + V(proxy) \ + V(getcwd) \ + V(runAsync) \ + V(writeToFile) \ + V(writeToTempFile) \ + V(readFromFile) \ + V(deleteFile) \ + V(connection) + +static QScriptValue Envjs_lineSource(QScriptContext *, QScriptEngine *) +{ + // Supposed to return the source text of the line causing the error. + //QScriptValue e = ctx->argument(0); + return "(line ?)"; +} + +static QScriptValue Envjs_eval(QScriptContext *ctx, QScriptEngine *eng) +{ + // Don't know what this is. this-object? Variable scope? + // QScriptValue scope = ctx->argument(0); + + QScriptValue source = ctx->argument(1); + QScriptValue sourceName = ctx->argument(0); + return eng->evaluate(source.toString(), sourceName.toString()); +} + +static QScriptValue Envjs_loadInlineScript(QScriptContext *ctx, QScriptEngine *) +{ + return ctx->throwError("loadInlineScript() not implemented"); +} + +static QScriptValue Envjs_loadLocalScript(QScriptContext *ctx, QScriptEngine *) +{ + return ctx->throwError("loadLocalScript() not implemented"); +} + +static QScriptValue Envjs_sync(QScriptContext *ctx, QScriptEngine *) +{ + return ctx->argument(0); +} + +static QScriptValue Envjs_spawn(QScriptContext *ctx, QScriptEngine *) +{ + QScriptValue fun = ctx->argument(0); + return fun.call(); +} + +class SleepyThread : public QThread +{ +public: + static void msleep(unsigned long msecs) + { QThread::msleep(msecs); } +}; + +static QScriptValue Envjs_sleep(QScriptContext *ctx, QScriptEngine *eng) +{ + uint msecs = ctx->argument(0).toUInt32(); + static_cast<SleepyThread*>(QThread::currentThread())->msleep(msecs); + return eng->undefinedValue(); +} + +static QScriptValue Envjs_loadFrame(QScriptContext *ctx, QScriptEngine *) +{ + return ctx->throwError("loadFrame() not implemented"); +} + +static QScriptValue Envjs_unloadFrame(QScriptContext *ctx, QScriptEngine *) +{ + return ctx->throwError("unloadFrame() not implemented"); +} + +static QScriptValue Envjs_proxy(QScriptContext *ctx, QScriptEngine *) +{ + return ctx->throwError("proxy() not implemented"); +} + +static QScriptValue Envjs_getcwd(QScriptContext *, QScriptEngine *) +{ + return QDir::currentPath(); +} + +class QtScriptFunctionInvoker : public QObject +{ + Q_OBJECT +public: + QtScriptFunctionInvoker(const QScriptValue &fn, QObject *parent = 0) + : QObject(parent), fun(fn) + {} + + void invokeLater() + { + QMetaObject::invokeMethod(this, "invoke", Qt::QueuedConnection); + } + +private slots: + void invoke() + { + fun.call(); + deleteLater(); + } + +private: + QScriptValue fun; +}; + +static QScriptValue Envjs_runAsync(QScriptContext *ctx, QScriptEngine *eng) +{ + QScriptValue fun = ctx->argument(0); + QtScriptFunctionInvoker *invoker = new QtScriptFunctionInvoker(fun, eng); + invoker->invokeLater(); + return eng->undefinedValue(); +} + +static QScriptValue Envjs_writeToFile(QScriptContext *ctx, QScriptEngine *eng) +{ + QScriptValue text = ctx->argument(0); + QScriptValue url = ctx->argument(1); + QString path = QUrl(url.toString()).toLocalFile(); + QFile file(path); + file.open(QIODevice::WriteOnly); + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + stream << text.toString(); + return eng->undefinedValue(); +} + +static QScriptValue Envjs_writeToTempFile(QScriptContext *ctx, QScriptEngine *) +{ +// QScriptValue text = ctx->argument(0); +// QScriptValue suffix = ctx->argument(1); +// QString fileName = QString::fromLatin1("envjs-tmp%0").arg(suffix.toString())); +// ### Create file and write text. File should be deleted when engine is. + return ctx->throwError("writeToTempFile() not implemented"); +} + +static QScriptValue Envjs_readFromFile(QScriptContext *ctx, QScriptEngine *) +{ + QScriptValue url = ctx->argument(0); + QString path = QUrl(url.toString()).toLocalFile(); + QFile file(path); + file.open(QIODevice::ReadOnly); + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + return stream.readAll(); +} + +static QScriptValue Envjs_deleteFile(QScriptContext *ctx, QScriptEngine *eng) +{ + QScriptValue url = ctx->argument(0); + QString path = QUrl(url.toString()).toLocalFile(); + QFile file(path); + file.remove(); + return eng->undefinedValue(); +} + +static QScriptValue Envjs_connection(QScriptContext *ctx, QScriptEngine *eng) +{ + // TODO: if xhr.async is true, all this stuff should be done in a + // delayed call or different thread, then the response handler can + // be called (in this thread). + + QScriptValue xhr = ctx->argument(0); + QScriptValue responseHandler = ctx->argument(1); + QScriptValue data = ctx->argument(2); + QUrl url = QUrl(xhr.property("url").toString()); + QNetworkAccessManager nam; // TODO: get a manager from somewhere... + QNetworkRequest req(url); + + QScriptValueIterator it(xhr.property("headers")); + while (it.hasNext()) { + it.next(); + req.setRawHeader(it.name().toUtf8(), it.value().toString().toUtf8()); + } + + QString method = xhr.property("method").toString(); + QNetworkReply *rep = 0; + if (method == QLatin1String("GET")) + rep = nam.get(req); + else if (method == QLatin1String("PUT")) + rep = nam.put(req, data.toString().toUtf8()); + else if (method == QLatin1String("POST")) + rep = nam.put(req, data.toString().toUtf8()); + else if (method == QLatin1String("HEAD")) + rep = nam.head(req); + else if (method == QLatin1String("DELETE")) + rep = nam.deleteResource(req); + else + return ctx->throwError(QString::fromLatin1("request method %0 not implemented").arg(method)); + // TODO: connect to reply's download/uploadProgress(), + // implement HEADERS_RECEIVED and LOADING states + + QEventLoop loop; + QObject::connect(rep, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + QScriptValue responseHeaders = xhr.property("responseHeaders"); + QList<QNetworkReply::RawHeaderPair> rawHeaderPairs = rep->rawHeaderPairs(); + for (int i = 0; i < rawHeaderPairs.size(); ++i) { + const QNetworkReply::RawHeaderPair &rhp = rawHeaderPairs.at(i); + responseHeaders.setProperty(QString::fromUtf8(rhp.first), QString::fromUtf8(rhp.second)); + } + + xhr.setProperty("readyState", 4); + QVariant statusCode = rep->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (statusCode.isValid()) + xhr.setProperty("status", statusCode.toInt()); + QVariant reasonPhrase = rep->attribute(QNetworkRequest::HttpReasonPhraseAttribute); + if (reasonPhrase.isValid()) + xhr.setProperty("statusText", reasonPhrase.toString()); + + QByteArray responseData = rep->readAll(); + xhr.setProperty("responseText", QString::fromUtf8(responseData)); + + if (responseHandler.isFunction()) + responseHandler.call(); + + return eng->undefinedValue(); +} + +void initializeEnvjsNatives(QScriptEngine *eng) +{ + QScriptValue envjs = eng->globalObject().property("Envjs"); + if (!envjs.isObject()) { + eng->currentContext()->throwError("env.js must be evaluated before natives can be initialized"); + return; + } + + envjs.setProperty("platform", "QtScript"); + + envjs.setProperty("log", eng->globalObject().property("print")); + +#define SET_ENVJS_FUNCTION(f) envjs.setProperty(#f, eng->newFunction(Envjs_##f)); + ENVJS_FUNCTIONS(SET_ENVJS_FUNCTION) +#undef SET_ENVJS_FUNCTION +} + +#include "envjsnatives.moc" |