summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Hansen <khansen@trolltech.com>2009-07-06 15:24:16 (GMT)
committerKent Hansen <khansen@trolltech.com>2009-07-06 15:24:16 (GMT)
commit0cac647b8b737709fcbd752d9d297ea485e69e2e (patch)
treee9bf6c9c8d10287e3bb9634e0196fbdcf973e10e
parentbd98c3e2f7117c9538c1c81e95e866358c92f44a (diff)
downloadQt-0cac647b8b737709fcbd752d9d297ea485e69e2e.zip
Qt-0cac647b8b737709fcbd752d9d297ea485e69e2e.tar.gz
Qt-0cac647b8b737709fcbd752d9d297ea485e69e2e.tar.bz2
start to implement QScriptEngine::importExtension()
-rw-r--r--src/script/api/qscriptengine.cpp205
-rw-r--r--tests/auto/qscriptengine/tst_qscriptengine.cpp1
2 files changed, 200 insertions, 6 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp
index 48142bb..2174136 100644
--- a/src/script/api/qscriptengine.cpp
+++ b/src/script/api/qscriptengine.cpp
@@ -49,6 +49,7 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qpluginloader.h>
#include <QtCore/qset.h>
+#include <QtCore/qtextstream.h>
#include "qscriptextensioninterface.h"
#endif
@@ -1936,8 +1937,16 @@ QScriptContext *QScriptEngine::currentContext() const
*/
QScriptContext *QScriptEngine::pushContext()
{
- qWarning("QScriptEngine::pushContext() not implemented");
- return 0;
+ Q_D(QScriptEngine);
+ QScriptContextPrivate *ctx_p = new QScriptContextPrivate(
+ /*callee=*/0, /*thisObject=*/d->scriptValueToJSCValue(globalObject()),
+ /*args=*/JSC::ArgList(), /*calledAsConstructor=*/false,
+ currentContext(), d);
+ d->currentContext = QScriptContextPrivate::create(*ctx_p);
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+// notifyContextPush(); TODO
+#endif
+ return d->currentContext;
}
/*!
@@ -1948,7 +1957,15 @@ QScriptContext *QScriptEngine::pushContext()
*/
void QScriptEngine::popContext()
{
- qWarning("QScriptEngine::popContext() not implemented");
+ Q_D(QScriptEngine);
+ if (!d->currentContext->parentContext())
+ return;
+ QScriptContext *popped = d->currentContext;
+ d->currentContext = popped->parentContext();
+ delete popped;
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+// notifyContextPop(); TODO
+#endif
}
/*!
@@ -2509,9 +2526,187 @@ void QScriptEngine::installTranslatorFunctions(const QScriptValue &object)
*/
QScriptValue QScriptEngine::importExtension(const QString &extension)
{
- qWarning("QScriptEngine::importExtension() not implemented");
+#if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
Q_UNUSED(extension);
- return QScriptValue();
+#else
+ Q_D(QScriptEngine);
+ if (d->importedExtensions.contains(extension))
+ return undefinedValue(); // already imported
+
+ QScriptContext *context = currentContext();
+ QCoreApplication *app = QCoreApplication::instance();
+ if (!app)
+ return context->throwError(QLatin1String("No application object"));
+
+ QObjectList staticPlugins = QPluginLoader::staticInstances();
+ QStringList libraryPaths = app->libraryPaths();
+ QString dot = QLatin1String(".");
+ QStringList pathComponents = extension.split(dot);
+ QString initDotJs = QLatin1String("__init__.js");
+
+ QString ext;
+ for (int i = 0; i < pathComponents.count(); ++i) {
+ if (!ext.isEmpty())
+ ext.append(dot);
+ ext.append(pathComponents.at(i));
+ if (d->importedExtensions.contains(ext))
+ continue; // already imported
+
+ if (d->extensionsBeingImported.contains(ext)) {
+ return context->throwError(QString::fromLatin1("recursive import of %0")
+ .arg(extension));
+ }
+ d->extensionsBeingImported.insert(ext);
+
+ QScriptExtensionInterface *iface = 0;
+ QString initjsContents;
+ QString initjsFileName;
+
+ // look for the extension in static plugins
+ for (int j = 0; j < staticPlugins.size(); ++j) {
+ iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(j));
+ if (!iface)
+ continue;
+ if (iface->keys().contains(ext))
+ break; // use this one
+ else
+ iface = 0; // keep looking
+ }
+
+ {
+ // look for __init__.js resource
+ QString path = QString::fromLatin1(":/qtscriptextension");
+ for (int j = 0; j <= i; ++j) {
+ path.append(QLatin1Char('/'));
+ path.append(pathComponents.at(j));
+ }
+ path.append(QLatin1Char('/'));
+ path.append(initDotJs);
+ QFile file(path);
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream ts(&file);
+ initjsContents = ts.readAll();
+ initjsFileName = path;
+ file.close();
+ }
+ }
+
+ if (!iface && initjsContents.isEmpty()) {
+ // look for the extension in library paths
+ for (int j = 0; j < libraryPaths.count(); ++j) {
+ QString libPath = libraryPaths.at(j) + QDir::separator() + QLatin1String("script");
+ QDir dir(libPath);
+ if (!dir.exists(dot))
+ continue;
+
+ // look for C++ plugin
+ QFileInfoList files = dir.entryInfoList(QDir::Files);
+ for (int k = 0; k < files.count(); ++k) {
+ QFileInfo entry = files.at(k);
+ QString filePath = entry.canonicalFilePath();
+ QPluginLoader loader(filePath);
+ iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
+ if (iface) {
+ if (iface->keys().contains(ext))
+ break; // use this one
+ else
+ iface = 0; // keep looking
+ }
+ }
+
+ // look for __init__.js in the corresponding dir
+ QDir dirdir(libPath);
+ bool dirExists = dirdir.exists();
+ for (int k = 0; dirExists && (k <= i); ++k)
+ dirExists = dirdir.cd(pathComponents.at(k));
+ if (dirExists && dirdir.exists(initDotJs)) {
+ QFile file(dirdir.canonicalPath()
+ + QDir::separator() + initDotJs);
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream ts(&file);
+ initjsContents = ts.readAll();
+ initjsFileName = file.fileName();
+ file.close();
+ }
+ }
+
+ if (iface || !initjsContents.isEmpty())
+ break;
+ }
+ }
+
+ if (!iface && initjsContents.isEmpty()) {
+ d->extensionsBeingImported.remove(ext);
+ return context->throwError(
+ QString::fromLatin1("Unable to import %0: no such extension")
+ .arg(extension));
+ }
+
+ // initialize the extension in a new context
+ QScriptContext *ctx = pushContext();
+ ctx->setThisObject(globalObject());
+#if 0 // ### implement me
+ ctx->setActivationObject(newActivationObject());
+ QScriptObject *activation_data = ctx_p->m_activation.m_object_value;
+ activation_data->m_scope = globalObject();
+
+ activation_data->m_members.resize(4);
+ activation_data->m_values.resize(4);
+ activation_data->m_members[0].object(
+ nameId(QLatin1String("__extension__")), 0,
+ QScriptValue::ReadOnly | QScriptValue::Undeletable);
+ activation_data->m_values[0] = QScriptValueImpl(this, ext);
+ activation_data->m_members[1].object(
+ nameId(QLatin1String("__setupPackage__")), 1, 0);
+ activation_data->m_values[1] = createFunction(__setupPackage__, 0, 0);
+ activation_data->m_members[2].object(
+ nameId(QLatin1String("__all__")), 2, 0);
+ activation_data->m_values[2] = undefinedValue();
+ activation_data->m_members[3].object(
+ nameId(QLatin1String("__postInit__")), 3, 0);
+ activation_data->m_values[3] = undefinedValue();
+#endif
+
+ // the script is evaluated first
+ if (!initjsContents.isEmpty()) {
+ QScriptValue ret = evaluate(initjsContents, initjsFileName);
+ if (hasUncaughtException()) {
+ popContext();
+ d->extensionsBeingImported.remove(ext);
+ return ret;
+ }
+ }
+
+ // next, the C++ plugin is called
+ if (iface) {
+ iface->initialize(ext, this);
+ if (hasUncaughtException()) {
+ QScriptValue ret = uncaughtException(); // ctx_p->returnValue();
+ popContext();
+ d->extensionsBeingImported.remove(ext);
+ return ret;
+ }
+ }
+
+ // if the __postInit__ function has been set, we call it
+ QScriptValue postInit = ctx->activationObject().property(QLatin1String("__postInit__"));
+ if (postInit.isFunction()) {
+ postInit.call(globalObject());
+ if (hasUncaughtException()) {
+ QScriptValue ret = uncaughtException(); // ctx_p->returnValue();
+ popContext();
+ d->extensionsBeingImported.remove(ext);
+ return ret;
+ }
+ }
+
+ popContext();
+
+ d->importedExtensions.insert(ext);
+ d->extensionsBeingImported.remove(ext);
+ } // for (i)
+#endif // QT_NO_QOBJECT
+ return undefinedValue();
}
/*!
diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp
index 4857569..6aab0e6 100644
--- a/tests/auto/qscriptengine/tst_qscriptengine.cpp
+++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp
@@ -163,7 +163,6 @@ void tst_QScriptEngine::currentContext()
void tst_QScriptEngine::pushPopContext()
{
- QSKIP("{push,pop}context() not implemented", SkipAll);
QScriptEngine eng;
QScriptContext *globalCtx = eng.currentContext();
QScriptContext *ctx = eng.pushContext();