diff options
Diffstat (limited to 'src/declarative/qml/qmlworkerscript.cpp')
-rw-r--r-- | src/declarative/qml/qmlworkerscript.cpp | 359 |
1 files changed, 227 insertions, 132 deletions
diff --git a/src/declarative/qml/qmlworkerscript.cpp b/src/declarative/qml/qmlworkerscript.cpp index a6428dd..d4fcf4a 100644 --- a/src/declarative/qml/qmlworkerscript.cpp +++ b/src/declarative/qml/qmlworkerscript.cpp @@ -55,15 +55,15 @@ class WorkerDataEvent : public QEvent public: enum Type { WorkerData = QEvent::User }; - WorkerDataEvent(int workerId, QmlWorkerScriptEngine::Data *data); + WorkerDataEvent(int workerId, const QVariant &data); virtual ~WorkerDataEvent(); int workerId() const; - QmlWorkerScriptEngine::Data *takeData(); + QVariant data() const; private: int m_id; - QmlWorkerScriptEngine::Data *m_data; + QVariant m_data; }; class WorkerLoadEvent : public QEvent @@ -81,31 +81,64 @@ private: QUrl m_url; }; +class WorkerRemoveEvent : public QEvent +{ +public: + enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 }; + + WorkerRemoveEvent(int workerId); + + int workerId() const; + +private: + int m_id; +}; + class QmlWorkerScriptEnginePrivate : public QObject { public: QmlWorkerScriptEnginePrivate(); - QScriptEngine *workerEngine; + struct ScriptEngine : public QScriptEngine + { + ScriptEngine(QmlWorkerScriptEnginePrivate *parent) : p(parent) {} + QmlWorkerScriptEnginePrivate *p; + }; + ScriptEngine *workerEngine; + static QmlWorkerScriptEnginePrivate *get(QScriptEngine *e) { + return static_cast<ScriptEngine *>(e)->p; + } QMutex m_lock; QWaitCondition m_wait; + struct WorkerScript { + WorkerScript(); + + int id; + bool initialized; + QmlWorkerScript *owner; + QScriptValue object; + + QScriptValue callback; + }; + + QHash<int, WorkerScript *> workers; QScriptValue getWorker(int); int m_nextId; - QHash<int, QScriptValue> m_workers; static QVariant scriptValueToVariant(const QScriptValue &); static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *); - static QScriptValue onmessage(QScriptContext *ctxt, QScriptEngine *engine); + static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine); + static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine); protected: virtual bool event(QEvent *); private: - void processMessage(int, QmlWorkerScriptEngine::Data *); + void processMessage(int, const QVariant &); void processLoad(int, const QUrl &); }; @@ -114,34 +147,75 @@ QmlWorkerScriptEnginePrivate::QmlWorkerScriptEnginePrivate() { } -QScriptValue QmlWorkerScriptEnginePrivate::onmessage(QScriptContext *ctxt, QScriptEngine *engine) +QScriptValue QmlWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine) { + QmlWorkerScriptEnginePrivate *p = QmlWorkerScriptEnginePrivate::get(engine); + + int id = ctxt->thisObject().data().toVariant().toInt(); + + WorkerScript *script = p->workers.value(id); + if (!script) + return engine->undefinedValue(); + if (ctxt->argumentCount() >= 1) - ctxt->thisObject().setData(ctxt->argument(0)); + script->callback = ctxt->argument(0); + + return script->callback; +} + +QScriptValue QmlWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (!ctxt->argumentCount()) + return engine->undefinedValue(); + + QmlWorkerScriptEnginePrivate *p = QmlWorkerScriptEnginePrivate::get(engine); + + int id = ctxt->thisObject().data().toVariant().toInt(); + + WorkerScript *script = p->workers.value(id); + if (!script) + return engine->undefinedValue(); - return ctxt->thisObject().data(); + p->m_lock.lock(); + if (script->owner) + QCoreApplication::postEvent(script->owner, + new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0)))); + p->m_lock.unlock(); + + return engine->undefinedValue(); } QScriptValue QmlWorkerScriptEnginePrivate::getWorker(int id) { - QHash<int, QScriptValue>::Iterator iter = m_workers.find(id); - if (iter == m_workers.end()) { - QScriptValue worker = workerEngine->newObject(); + QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id); + + if (iter == workers.end()) + return workerEngine->nullValue(); + + WorkerScript *script = *iter; + if (!script->initialized) { - worker.setProperty(QLatin1String("onmessage"), workerEngine->newFunction(onmessage), - QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + script->initialized = true; + script->object = workerEngine->newObject(); - iter = m_workers.insert(id, worker); + QScriptValue api = workerEngine->newObject(); + api.setData(script->id); + + api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage), + QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage)); + + script->object.setProperty(QLatin1String("WorkerScript"), api); } - return *iter; + return script->object; } bool QmlWorkerScriptEnginePrivate::event(QEvent *event) { if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); - processMessage(workerEvent->workerId(), workerEvent->takeData()); + processMessage(workerEvent->workerId(), workerEvent->data()); return true; } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) { WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event); @@ -152,19 +226,18 @@ bool QmlWorkerScriptEnginePrivate::event(QEvent *event) } } -void QmlWorkerScriptEnginePrivate::processMessage(int id, QmlWorkerScriptEngine::Data *data) +void QmlWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data) { - QScriptValue worker = getWorker(id); - QScriptValue onmessage = worker.data(); + WorkerScript *script = workers.value(id); + if (!script) + return; - if (onmessage.isFunction()) { + if (script->callback.isFunction()) { QScriptValue args = workerEngine->newArray(1); - args.setProperty(0, variantToScriptValue(data->var, workerEngine)); + args.setProperty(0, variantToScriptValue(data, workerEngine)); - onmessage.call(worker, args); + script->callback.call(script->object, args); } - - if (data) delete data; } void QmlWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) @@ -190,14 +263,80 @@ void QmlWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) } } -WorkerDataEvent::WorkerDataEvent(int workerId, QmlWorkerScriptEngine::Data *data) +QVariant QmlWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value) +{ + if (value.isBool()) { + return QVariant(value.toBool()); + } else if (value.isString()) { + return QVariant(value.toString()); + } else if (value.isNumber()) { + return QVariant((qreal)value.toNumber()); + } else if (value.isArray()) { + QVariantList list; + + quint32 length = (quint32)value.property("length").toNumber(); + + for (quint32 ii = 0; ii < length; ++ii) { + QVariant v = scriptValueToVariant(ii); + list << v; + } + + return QVariant(list); + } else if (value.isObject()) { + QVariantHash hash; + + QScriptValueIterator iter(value); + + while (iter.hasNext()) { + iter.next(); + hash.insert(iter.name(), scriptValueToVariant(iter.value())); + } + + return QVariant(hash); + } + + return QVariant(); + +} + +QScriptValue QmlWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine) +{ + if (value.type() == QVariant::Bool) { + return QScriptValue(value.toBool()); + } else if (value.type() == QVariant::String) { + return QScriptValue(value.toString()); + } else if (value.type() == (QVariant::Type)QMetaType::QReal) { + return QScriptValue(value.toReal()); + } else if (value.type() == (QVariant::Type)QMetaType::QVariantList) { + QVariantList list = qvariant_cast<QVariantList>(value); + QScriptValue rv = engine->newArray(list.count()); + + for (quint32 ii = 0; ii < list.count(); ++ii) + rv.setProperty(ii, variantToScriptValue(list.at(ii), engine)); + + return rv; + } else if (value.type() == (QVariant::Type)QMetaType::QVariantHash) { + + QVariantHash hash = qvariant_cast<QVariantHash>(value); + + QScriptValue rv = engine->newObject(); + + for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter) + rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine)); + + return rv; + } else { + return engine->nullValue(); + } +} + +WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data) : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data) { } WorkerDataEvent::~WorkerDataEvent() { - if (m_data) { delete m_data; m_data = 0; } } int WorkerDataEvent::workerId() const @@ -205,11 +344,9 @@ int WorkerDataEvent::workerId() const return m_id; } -QmlWorkerScriptEngine::Data *WorkerDataEvent::takeData() +QVariant WorkerDataEvent::data() const { - QmlWorkerScriptEngine::Data *rv = m_data; - m_data = 0; - return rv; + return m_data; } WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url) @@ -227,6 +364,16 @@ QUrl WorkerLoadEvent::url() const return m_url; } +WorkerRemoveEvent::WorkerRemoveEvent(int workerId) +: QEvent((QEvent::Type)WorkerRemove), m_id(workerId) +{ +} + +int WorkerRemoveEvent::workerId() const +{ + return m_id; +} + QmlWorkerScriptEngine::QmlWorkerScriptEngine(QObject *parent) : QThread(parent), d(new QmlWorkerScriptEnginePrivate) { @@ -234,6 +381,7 @@ QmlWorkerScriptEngine::QmlWorkerScriptEngine(QObject *parent) start(QThread::LowPriority); d->m_wait.wait(&d->m_lock); d->moveToThread(this); + d->m_lock.unlock(); } QmlWorkerScriptEngine::~QmlWorkerScriptEngine() @@ -241,48 +389,44 @@ QmlWorkerScriptEngine::~QmlWorkerScriptEngine() delete d; d = 0; } -QmlWorkerScriptEngine::WorkerScript::WorkerScript() -: engine(0), id(0) +QmlWorkerScriptEnginePrivate::WorkerScript::WorkerScript() +: id(-1), initialized(false), owner(0) { } -void QmlWorkerScriptEngine::WorkerScript::executeUrl(const QUrl &url) +int QmlWorkerScriptEngine::registerWorkerScript(QmlWorkerScript *owner) { - engine->executeUrl(this, url); -} + QmlWorkerScriptEnginePrivate::WorkerScript *script = new QmlWorkerScriptEnginePrivate::WorkerScript; + script->id = d->m_nextId++; + script->owner = owner; -void QmlWorkerScriptEngine::WorkerScript::sendMessage(Data *data) -{ - engine->sendMessage(this, data); + d->m_lock.lock(); + d->workers.insert(script->id, script); + d->m_lock.unlock(); + + return script->id; } -void QmlWorkerScriptEngine::executeUrl(WorkerScript *script, const QUrl &data) +void QmlWorkerScriptEngine::removeWorkerScript(int id) { - QCoreApplication::postEvent(d, new WorkerLoadEvent(script->id, data)); + QCoreApplication::postEvent(d, new WorkerRemoveEvent(id)); } -/*! - Ownership of \a data transfers to QmlWorkerScriptEngine. It can not be modified by - the caller. -*/ -void QmlWorkerScriptEngine::sendMessage(WorkerScript *script, Data *data) +void QmlWorkerScriptEngine::executeUrl(int id, const QUrl &url) { - QCoreApplication::postEvent(d, new WorkerDataEvent(script->id, data)); + QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url)); } -QmlWorkerScriptEngine::WorkerScript *QmlWorkerScriptEngine::createWorkerScript() +void QmlWorkerScriptEngine::sendMessage(int id, const QVariant &data) { - WorkerScript *rv = new WorkerScript; - rv->engine = this; - rv->id = d->m_nextId++; - return rv; + QCoreApplication::postEvent(d, new WorkerDataEvent(id, data)); } void QmlWorkerScriptEngine::run() { d->m_lock.lock(); - d->workerEngine = new QScriptEngine; + d->workerEngine = new QmlWorkerScriptEnginePrivate::ScriptEngine(d); d->m_wait.wakeAll(); @@ -294,80 +438,13 @@ void QmlWorkerScriptEngine::run() } QmlWorkerScript::QmlWorkerScript(QObject *parent) -: QObject(parent), m_script(0) +: QObject(parent), m_engine(0), m_scriptId(-1) { } QmlWorkerScript::~QmlWorkerScript() { - if (m_script) { delete m_script; m_script = 0; } -} - -QVariant QmlWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value) -{ - if (value.isBool()) { - return QVariant(value.toBool()); - } else if (value.isString()) { - return QVariant(value.toString()); - } else if (value.isNumber()) { - return QVariant((qreal)value.toNumber()); - } else if (value.isArray()) { - QVariantList list; - - quint32 length = (quint32)value.property("length").toNumber(); - - for (quint32 ii = 0; ii < length; ++ii) { - QVariant v = scriptValueToVariant(ii); - list << v; - } - - return QVariant(list); - } else if (value.isObject()) { - QVariantHash hash; - - QScriptValueIterator iter(value); - - while (iter.hasNext()) { - iter.next(); - hash.insert(iter.name(), scriptValueToVariant(iter.value())); - } - - return QVariant(hash); - } - - return QVariant(); - -} - -QScriptValue QmlWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine) -{ - if (value.type() == QVariant::Bool) { - return QScriptValue(value.toBool()); - } else if (value.type() == QVariant::String) { - return QScriptValue(value.toString()); - } else if (value.type() == (QVariant::Type)QMetaType::QReal) { - return QScriptValue(value.toReal()); - } else if (value.type() == (QVariant::Type)QMetaType::QVariantList) { - QVariantList list = qvariant_cast<QVariantList>(value); - QScriptValue rv = engine->newArray(list.count()); - - for (quint32 ii = 0; ii < list.count(); ++ii) - rv.setProperty(ii, variantToScriptValue(list.at(ii), engine)); - - return rv; - } else if (value.type() == (QVariant::Type)QMetaType::QVariantHash) { - - QVariantHash hash = qvariant_cast<QVariantHash>(value); - - QScriptValue rv = engine->newObject(); - - for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter) - rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine)); - - return rv; - } else { - return engine->nullValue(); - } + if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId); } QUrl QmlWorkerScript::source() const @@ -382,37 +459,55 @@ void QmlWorkerScript::setSource(const QUrl &source) m_source = source; - if (m_script) - m_script->executeUrl(m_source); + if (m_engine) + m_engine->executeUrl(m_scriptId, m_source); emit sourceChanged(); } void QmlWorkerScript::sendMessage(const QScriptValue &message) { - if (!m_script) { + if (!m_engine) { qWarning("QmlWorkerScript: Attempt to send message before WorkerScript establishment"); return; } - QmlWorkerScriptEngine::Data *data = new QmlWorkerScriptEngine::Data; - data->var = QmlWorkerScriptEnginePrivate::scriptValueToVariant(message); - m_script->sendMessage(data); + m_engine->sendMessage(m_scriptId, QmlWorkerScriptEnginePrivate::scriptValueToVariant(message)); } void QmlWorkerScript::componentComplete() { - if (!m_script) { + if (!m_engine) { QmlEngine *engine = qmlEngine(this); if (!engine) { qWarning("QmlWorkerScript: componentComplete() called without qmlEngine() set"); return; } - m_script = QmlEnginePrivate::get(engine)->getWorkerScriptEngine()->createWorkerScript(); + + m_engine = QmlEnginePrivate::get(engine)->getWorkerScriptEngine(); + m_scriptId = m_engine->registerWorkerScript(this); if (m_source.isValid()) - m_script->executeUrl(m_source); + m_engine->executeUrl(m_scriptId, m_source); } } +bool QmlWorkerScript::event(QEvent *event) +{ + if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { + QmlEngine *engine = qmlEngine(this); + if (engine) { + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); + QScriptValue value = + QmlWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine); + emit message(value); + } + return true; + } else { + return QObject::event(event); + } +} + + QML_DEFINE_TYPE(Qt, 4, 6, WorkerScript, QmlWorkerScript); |