src/declarative/qml/qdeclarativeworkerscript.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "private/qdeclarativeworkerscript_p.h"
       
    43 #include "private/qdeclarativelistmodel_p.h"
       
    44 #include "private/qdeclarativelistmodelworkeragent_p.h"
       
    45 #include "private/qdeclarativeengine_p.h"
       
    46 
       
    47 #include <QtCore/qcoreevent.h>
       
    48 #include <QtCore/qcoreapplication.h>
       
    49 #include <QtCore/qdebug.h>
       
    50 #include <QtScript/qscriptengine.h>
       
    51 #include <QtCore/qmutex.h>
       
    52 #include <QtCore/qwaitcondition.h>
       
    53 #include <QtScript/qscriptvalueiterator.h>
       
    54 #include <QtCore/qfile.h>
       
    55 #include <QtNetwork/qnetworkaccessmanager.h>
       
    56 #include <QtDeclarative/qdeclarativeinfo.h>
       
    57 #include "qdeclarativenetworkaccessmanagerfactory.h"
       
    58 
       
    59 
       
    60 QT_BEGIN_NAMESPACE
       
    61 
       
    62 class WorkerDataEvent : public QEvent
       
    63 {
       
    64 public:
       
    65     enum Type { WorkerData = QEvent::User };
       
    66 
       
    67     WorkerDataEvent(int workerId, const QVariant &data);
       
    68     virtual ~WorkerDataEvent();
       
    69 
       
    70     int workerId() const;
       
    71     QVariant data() const;
       
    72 
       
    73 private:
       
    74     int m_id;
       
    75     QVariant m_data;
       
    76 };
       
    77 
       
    78 class WorkerLoadEvent : public QEvent
       
    79 {
       
    80 public:
       
    81     enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 };
       
    82 
       
    83     WorkerLoadEvent(int workerId, const QUrl &url);
       
    84 
       
    85     int workerId() const;
       
    86     QUrl url() const;
       
    87 
       
    88 private:
       
    89     int m_id;
       
    90     QUrl m_url;
       
    91 };
       
    92 
       
    93 class WorkerRemoveEvent : public QEvent
       
    94 {
       
    95 public:
       
    96     enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
       
    97 
       
    98     WorkerRemoveEvent(int workerId);
       
    99 
       
   100     int workerId() const;
       
   101 
       
   102 private:
       
   103     int m_id;
       
   104 };
       
   105 
       
   106 class QDeclarativeWorkerScriptEnginePrivate : public QObject
       
   107 {
       
   108     Q_OBJECT
       
   109 public:
       
   110     enum WorkerEventTypes {
       
   111         WorkerDestroyEvent = QEvent::User + 100
       
   112     };
       
   113 
       
   114     QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng);
       
   115 
       
   116     struct ScriptEngine : public QDeclarativeScriptEngine
       
   117     {
       
   118         ScriptEngine(QDeclarativeWorkerScriptEnginePrivate *parent) : QDeclarativeScriptEngine(0), p(parent), accessManager(0) {}
       
   119         ~ScriptEngine() { delete accessManager; }
       
   120         QDeclarativeWorkerScriptEnginePrivate *p;
       
   121         QNetworkAccessManager *accessManager;
       
   122 
       
   123         virtual QNetworkAccessManager *networkAccessManager() {
       
   124             if (!accessManager) {
       
   125                 if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
       
   126                     accessManager = p->qmlengine->networkAccessManagerFactory()->create(this);
       
   127                 } else {
       
   128                     accessManager = new QNetworkAccessManager(this);
       
   129                 }
       
   130             }
       
   131             return accessManager;
       
   132         }
       
   133     };
       
   134     ScriptEngine *workerEngine;
       
   135     static QDeclarativeWorkerScriptEnginePrivate *get(QScriptEngine *e) {
       
   136         return static_cast<ScriptEngine *>(e)->p;
       
   137     }
       
   138 
       
   139     QDeclarativeEngine *qmlengine;
       
   140 
       
   141     QMutex m_lock;
       
   142     QWaitCondition m_wait;
       
   143 
       
   144     struct WorkerScript {
       
   145         WorkerScript();
       
   146 
       
   147         int id;
       
   148         bool initialized;
       
   149         QDeclarativeWorkerScript *owner;
       
   150         QScriptValue object;
       
   151 
       
   152         QScriptValue callback;
       
   153     };
       
   154 
       
   155     QHash<int, WorkerScript *> workers;
       
   156     QScriptValue getWorker(int);
       
   157 
       
   158     int m_nextId;
       
   159 
       
   160     static QVariant scriptValueToVariant(const QScriptValue &);
       
   161     static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *);
       
   162 
       
   163     static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine);
       
   164     static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine);
       
   165 
       
   166 signals:
       
   167     void stopThread();
       
   168 
       
   169 protected:
       
   170     virtual bool event(QEvent *);
       
   171 
       
   172 private:
       
   173     void processMessage(int, const QVariant &);
       
   174     void processLoad(int, const QUrl &);
       
   175 };
       
   176 
       
   177 QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
       
   178 : workerEngine(0), qmlengine(engine), m_nextId(0)
       
   179 {
       
   180 }
       
   181 
       
   182 QScriptValue QDeclarativeWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine)
       
   183 {
       
   184     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
       
   185 
       
   186     int id = ctxt->thisObject().data().toVariant().toInt();
       
   187 
       
   188     WorkerScript *script = p->workers.value(id);
       
   189     if (!script)
       
   190         return engine->undefinedValue();
       
   191 
       
   192     if (ctxt->argumentCount() >= 1) 
       
   193         script->callback = ctxt->argument(0);
       
   194 
       
   195     return script->callback;
       
   196 }
       
   197 
       
   198 QScriptValue QDeclarativeWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine)
       
   199 {
       
   200     if (!ctxt->argumentCount())
       
   201         return engine->undefinedValue();
       
   202 
       
   203     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
       
   204 
       
   205     int id = ctxt->thisObject().data().toVariant().toInt();
       
   206 
       
   207     WorkerScript *script = p->workers.value(id);
       
   208     if (!script)
       
   209         return engine->undefinedValue();
       
   210 
       
   211     QMutexLocker(&p->m_lock);
       
   212 
       
   213     if (script->owner)
       
   214         QCoreApplication::postEvent(script->owner,
       
   215                                     new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0))));
       
   216 
       
   217     return engine->undefinedValue();
       
   218 }
       
   219 
       
   220 QScriptValue QDeclarativeWorkerScriptEnginePrivate::getWorker(int id)
       
   221 {
       
   222     QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id);
       
   223 
       
   224     if (iter == workers.end())
       
   225         return workerEngine->nullValue();
       
   226 
       
   227     WorkerScript *script = *iter;
       
   228     if (!script->initialized) {
       
   229 
       
   230         script->initialized = true;
       
   231         script->object = workerEngine->newObject();
       
   232 
       
   233         QScriptValue api = workerEngine->newObject();
       
   234         api.setData(script->id);
       
   235 
       
   236         api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage),
       
   237                         QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
       
   238         api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage));
       
   239 
       
   240         script->object.setProperty(QLatin1String("WorkerScript"), api);
       
   241     }
       
   242 
       
   243     return script->object;
       
   244 }
       
   245 
       
   246 bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
       
   247 {
       
   248     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
       
   249         WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
       
   250         processMessage(workerEvent->workerId(), workerEvent->data());
       
   251         return true;
       
   252     } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
       
   253         WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
       
   254         processLoad(workerEvent->workerId(), workerEvent->url());
       
   255         return true;
       
   256     } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
       
   257         emit stopThread();
       
   258         return true;
       
   259     } else {
       
   260         return QObject::event(event);
       
   261     }
       
   262 }
       
   263 
       
   264 void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data)
       
   265 {
       
   266     WorkerScript *script = workers.value(id);
       
   267     if (!script)
       
   268         return;
       
   269 
       
   270     if (script->callback.isFunction()) {
       
   271         QScriptValue args = workerEngine->newArray(1);
       
   272         args.setProperty(0, variantToScriptValue(data, workerEngine));
       
   273 
       
   274         script->callback.call(script->object, args);
       
   275     }
       
   276 }
       
   277 
       
   278 void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
       
   279 {
       
   280     if (url.isRelative())
       
   281         return;
       
   282 
       
   283     QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
       
   284 
       
   285     QFile f(fileName);
       
   286     if (f.open(QIODevice::ReadOnly)) {
       
   287         QByteArray data = f.readAll();
       
   288         QString script = QString::fromUtf8(data);
       
   289 
       
   290         QScriptValue activation = getWorker(id);
       
   291 
       
   292         QScriptContext *ctxt = QScriptDeclarativeClass::pushCleanContext(workerEngine);
       
   293         QScriptValue urlContext = workerEngine->newObject();
       
   294         urlContext.setData(QScriptValue(workerEngine, fileName));
       
   295         ctxt->pushScope(urlContext);
       
   296         ctxt->pushScope(activation);
       
   297         ctxt->setActivationObject(activation);
       
   298 
       
   299         workerEngine->baseUrl = url;
       
   300         workerEngine->evaluate(script);
       
   301 
       
   302         workerEngine->popContext();
       
   303     } else {
       
   304         qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
       
   305     }
       
   306 }
       
   307 
       
   308 QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value)
       
   309 {
       
   310     if (value.isBool()) {
       
   311         return QVariant(value.toBool());
       
   312     } else if (value.isString()) {
       
   313         return QVariant(value.toString());
       
   314     } else if (value.isNumber()) {
       
   315         return QVariant((qreal)value.toNumber());
       
   316     } else if (value.isArray()) {
       
   317         QVariantList list;
       
   318 
       
   319         quint32 length = (quint32)value.property(QLatin1String("length")).toNumber();
       
   320 
       
   321         for (quint32 ii = 0; ii < length; ++ii) {
       
   322             QVariant v = scriptValueToVariant(value.property(ii));
       
   323             list << v;
       
   324         }
       
   325 
       
   326         return QVariant(list);
       
   327     } else if (value.isQObject()) {
       
   328         QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject());
       
   329         if (lm) {
       
   330             QDeclarativeListModelWorkerAgent *agent = lm->agent();
       
   331             if (agent) {
       
   332                 QDeclarativeListModelWorkerAgent::VariantRef v(agent);
       
   333                 return qVariantFromValue(v);
       
   334             } else {
       
   335                 return QVariant();
       
   336             }
       
   337         } else {
       
   338             // No other QObject's are allowed to be sent
       
   339             return QVariant();
       
   340         }
       
   341     } else if (value.isObject()) {
       
   342         QVariantHash hash;
       
   343 
       
   344         QScriptValueIterator iter(value);
       
   345 
       
   346         while (iter.hasNext()) {
       
   347             iter.next();
       
   348             hash.insert(iter.name(), scriptValueToVariant(iter.value()));
       
   349         }
       
   350 
       
   351         return QVariant(hash);
       
   352     }
       
   353 
       
   354     return QVariant();
       
   355 
       
   356 }
       
   357 
       
   358 QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine)
       
   359 {
       
   360     if (value.userType() == QVariant::Bool) {
       
   361         return QScriptValue(value.toBool());
       
   362     } else if (value.userType() == QVariant::String) {
       
   363         return QScriptValue(value.toString());
       
   364     } else if (value.userType() == QMetaType::QReal) {
       
   365         return QScriptValue(value.toReal());
       
   366     } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) {
       
   367         QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value);
       
   368         if (vr.a->scriptEngine() == 0)
       
   369             vr.a->setScriptEngine(engine);
       
   370         else if (vr.a->scriptEngine() != engine)
       
   371             return engine->nullValue();
       
   372         QScriptValue o = engine->newQObject(vr.a);
       
   373         o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc
       
   374         return o;
       
   375     } else if (value.userType() == QMetaType::QVariantList) {
       
   376         QVariantList list = qvariant_cast<QVariantList>(value);
       
   377         QScriptValue rv = engine->newArray(list.count());
       
   378 
       
   379         for (quint32 ii = 0; ii < quint32(list.count()); ++ii)
       
   380             rv.setProperty(ii, variantToScriptValue(list.at(ii), engine));
       
   381 
       
   382         return rv;
       
   383     } else if (value.userType() == QMetaType::QVariantHash) {
       
   384 
       
   385         QVariantHash hash = qvariant_cast<QVariantHash>(value);
       
   386 
       
   387         QScriptValue rv = engine->newObject();
       
   388 
       
   389         for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter)
       
   390             rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine));
       
   391 
       
   392         return rv;
       
   393     } else {
       
   394         return engine->nullValue();
       
   395     }
       
   396 }
       
   397 
       
   398 WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data)
       
   399 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
       
   400 {
       
   401 }
       
   402 
       
   403 WorkerDataEvent::~WorkerDataEvent()
       
   404 {
       
   405 }
       
   406 
       
   407 int WorkerDataEvent::workerId() const
       
   408 {
       
   409     return m_id;
       
   410 }
       
   411 
       
   412 QVariant WorkerDataEvent::data() const
       
   413 {
       
   414     return m_data;
       
   415 }
       
   416 
       
   417 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
       
   418 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
       
   419 {
       
   420 }
       
   421 
       
   422 int WorkerLoadEvent::workerId() const
       
   423 {
       
   424     return m_id;
       
   425 }
       
   426 
       
   427 QUrl WorkerLoadEvent::url() const
       
   428 {
       
   429     return m_url;
       
   430 }
       
   431 
       
   432 WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
       
   433 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
       
   434 {
       
   435 }
       
   436 
       
   437 int WorkerRemoveEvent::workerId() const
       
   438 {
       
   439     return m_id;
       
   440 }
       
   441 
       
   442 QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent)
       
   443 : QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent))
       
   444 {
       
   445     d->m_lock.lock();
       
   446     connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
       
   447     start(QThread::LowPriority);
       
   448     d->m_wait.wait(&d->m_lock);
       
   449     d->moveToThread(this);
       
   450     d->m_lock.unlock();
       
   451 }
       
   452 
       
   453 QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine()
       
   454 {
       
   455     d->m_lock.lock();
       
   456     qDeleteAll(d->workers);
       
   457     d->workers.clear();
       
   458     QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent));
       
   459     d->m_lock.unlock();
       
   460 
       
   461     wait();
       
   462     d->deleteLater();
       
   463 }
       
   464 
       
   465 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
       
   466 : id(-1), initialized(false), owner(0)
       
   467 {
       
   468 }
       
   469 
       
   470 int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
       
   471 {
       
   472     QDeclarativeWorkerScriptEnginePrivate::WorkerScript *script = new QDeclarativeWorkerScriptEnginePrivate::WorkerScript;
       
   473     script->id = d->m_nextId++;
       
   474     script->owner = owner;
       
   475 
       
   476     d->m_lock.lock();
       
   477     d->workers.insert(script->id, script);
       
   478     d->m_lock.unlock();
       
   479 
       
   480     return script->id;
       
   481 }
       
   482 
       
   483 void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id)
       
   484 {
       
   485     QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
       
   486 }
       
   487 
       
   488 void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url)
       
   489 {
       
   490     QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
       
   491 }
       
   492 
       
   493 void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QVariant &data)
       
   494 {
       
   495     QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
       
   496 }
       
   497 
       
   498 void QDeclarativeWorkerScriptEngine::run()
       
   499 {
       
   500     d->m_lock.lock();
       
   501 
       
   502     d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::ScriptEngine(d);
       
   503 
       
   504     d->m_wait.wakeAll();
       
   505 
       
   506     d->m_lock.unlock();
       
   507 
       
   508     exec();
       
   509 
       
   510     delete d->workerEngine; d->workerEngine = 0;
       
   511 }
       
   512 
       
   513 
       
   514 /*!
       
   515     \qmlclass WorkerScript QDeclarativeWorkerScript
       
   516     \brief The WorkerScript element enables the use of threads in QML.
       
   517 
       
   518     Use WorkerScript to run operations in a new thread.
       
   519     This is useful for running operations in the background so
       
   520     that the main GUI thread is not blocked.
       
   521 
       
   522     Messages can be passed between the new thread and the parent thread
       
   523     using sendMessage() and the onMessage() handler.
       
   524 
       
   525     Here is an example:
       
   526 
       
   527     \snippet doc/src/snippets/declarative/workerscript.qml 0
       
   528 
       
   529     The above worker script specifies a javascript file, "script.js", that handles
       
   530     the operations to be performed in the new thread. Here is \c script.js:
       
   531 
       
   532     \qml
       
   533     WorkerScript.onMessage = function(message) {
       
   534         // ... long-running operations and calculations are done here
       
   535         WorkerScript.sendMessage({ 'reply': 'Mouse is at ' + message.x + ',' + message.y })
       
   536     }
       
   537     \endqml
       
   538 
       
   539     When the user clicks anywhere within the rectangle, \c sendMessage() is
       
   540     called, triggering the \tt WorkerScript.onMessage() handler in
       
   541     \tt script.js. This in turn sends a reply message that is then received
       
   542     by the \tt onMessage() handler of \tt myWorker.
       
   543 */
       
   544 QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent)
       
   545 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
       
   546 {
       
   547 }
       
   548 
       
   549 QDeclarativeWorkerScript::~QDeclarativeWorkerScript()
       
   550 {
       
   551     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
       
   552 }
       
   553 
       
   554 /*!
       
   555     \qmlproperty url WorkerScript::source
       
   556 
       
   557     This holds the url of the javascript file that implements the
       
   558     \tt WorkerScript.onMessage() handler for threaded operations.
       
   559 */
       
   560 QUrl QDeclarativeWorkerScript::source() const
       
   561 {
       
   562     return m_source;
       
   563 }
       
   564 
       
   565 void QDeclarativeWorkerScript::setSource(const QUrl &source)
       
   566 {
       
   567     if (m_source == source)
       
   568         return;
       
   569 
       
   570     m_source = source;
       
   571 
       
   572     if (engine())
       
   573         m_engine->executeUrl(m_scriptId, m_source);
       
   574 
       
   575     emit sourceChanged();
       
   576 }
       
   577 
       
   578 /*
       
   579     \qmlmethod WorkerScript::sendMessage(jsobject message)
       
   580 
       
   581     Sends the given \a message to a worker script handler in another
       
   582     thread. The other worker script handler can receive this message
       
   583     through the onMessage() handler.
       
   584 */
       
   585 void QDeclarativeWorkerScript::sendMessage(const QScriptValue &message)
       
   586 {
       
   587     if (!engine()) {
       
   588         qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
       
   589         return;
       
   590     }
       
   591 
       
   592     m_engine->sendMessage(m_scriptId, QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(message));
       
   593 }
       
   594 
       
   595 void QDeclarativeWorkerScript::classBegin()
       
   596 {
       
   597     m_componentComplete = false;
       
   598 }
       
   599 
       
   600 QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine()
       
   601 {
       
   602     if (m_engine) return m_engine;
       
   603     if (m_componentComplete) {
       
   604         QDeclarativeEngine *engine = qmlEngine(this);
       
   605         if (!engine) {
       
   606             qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set");
       
   607             return 0;
       
   608         }
       
   609 
       
   610         m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine();
       
   611         m_scriptId = m_engine->registerWorkerScript(this);
       
   612 
       
   613         if (m_source.isValid())
       
   614             m_engine->executeUrl(m_scriptId, m_source);
       
   615 
       
   616         return m_engine;
       
   617     }
       
   618     return 0;
       
   619 }
       
   620 
       
   621 void QDeclarativeWorkerScript::componentComplete()
       
   622 {
       
   623     m_componentComplete = true;
       
   624     engine(); // Get it started now.
       
   625 }
       
   626 
       
   627 /*!
       
   628     \qmlsignal WorkerScript::onMessage(jsobject msg)
       
   629 
       
   630     This handler is called when a message \a msg is received from a worker
       
   631     script in another thread through a call to sendMessage().
       
   632 */
       
   633 
       
   634 bool QDeclarativeWorkerScript::event(QEvent *event)
       
   635 {
       
   636     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
       
   637         QDeclarativeEngine *engine = qmlEngine(this);
       
   638         if (engine) {
       
   639             QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
       
   640             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
       
   641             QScriptValue value =
       
   642                 QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine);
       
   643             emit message(value);
       
   644         }
       
   645         return true;
       
   646     } else {
       
   647         return QObject::event(event);
       
   648     }
       
   649 }
       
   650 
       
   651 QT_END_NAMESPACE
       
   652 
       
   653 #include <qdeclarativeworkerscript.moc>
       
   654