/**************************************************************************** ** ** 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 #include #include // 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(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 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"