Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeworkerscript.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 #include "private/qdeclarativeexpression_p.h"
47
48 #include <QtCore/qcoreevent.h>
49 #include <QtCore/qcoreapplication.h>
50 #include <QtCore/qdebug.h>
51 #include <QtScript/qscriptengine.h>
52 #include <QtCore/qmutex.h>
53 #include <QtCore/qwaitcondition.h>
54 #include <QtScript/qscriptvalueiterator.h>
55 #include <QtCore/qfile.h>
56 #include <QtCore/qdatetime.h>
57 #include <QtNetwork/qnetworkaccessmanager.h>
58 #include <QtDeclarative/qdeclarativeinfo.h>
59 #include "qdeclarativenetworkaccessmanagerfactory.h"
60
61
62 QT_BEGIN_NAMESPACE
63
64 class WorkerDataEvent : public QEvent
65 {
66 public:
67     enum Type { WorkerData = QEvent::User };
68
69     WorkerDataEvent(int workerId, const QVariant &data);
70     virtual ~WorkerDataEvent();
71
72     int workerId() const;
73     QVariant data() const;
74
75 private:
76     int m_id;
77     QVariant m_data;
78 };
79
80 class WorkerLoadEvent : public QEvent
81 {
82 public:
83     enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 };
84
85     WorkerLoadEvent(int workerId, const QUrl &url);
86
87     int workerId() const;
88     QUrl url() const;
89
90 private:
91     int m_id;
92     QUrl m_url;
93 };
94
95 class WorkerRemoveEvent : public QEvent
96 {
97 public:
98     enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
99
100     WorkerRemoveEvent(int workerId);
101
102     int workerId() const;
103
104 private:
105     int m_id;
106 };
107
108 class WorkerErrorEvent : public QEvent
109 {
110 public:
111     enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 };
112
113     WorkerErrorEvent(const QDeclarativeError &error);
114
115     QDeclarativeError error() const;
116
117 private:
118     QDeclarativeError m_error;
119 };
120
121 class QDeclarativeWorkerScriptEnginePrivate : public QObject
122 {
123     Q_OBJECT
124 public:
125     enum WorkerEventTypes {
126         WorkerDestroyEvent = QEvent::User + 100
127     };
128
129     QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng);
130
131     struct ScriptEngine : public QDeclarativeScriptEngine
132     {
133         ScriptEngine(QDeclarativeWorkerScriptEnginePrivate *parent) : QDeclarativeScriptEngine(0), p(parent), accessManager(0) {}
134         ~ScriptEngine() { delete accessManager; }
135         QDeclarativeWorkerScriptEnginePrivate *p;
136         QNetworkAccessManager *accessManager;
137
138         virtual QNetworkAccessManager *networkAccessManager() {
139             if (!accessManager) {
140                 if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
141                     accessManager = p->qmlengine->networkAccessManagerFactory()->create(this);
142                 } else {
143                     accessManager = new QNetworkAccessManager(this);
144                 }
145             }
146             return accessManager;
147         }
148     };
149     ScriptEngine *workerEngine;
150     static QDeclarativeWorkerScriptEnginePrivate *get(QScriptEngine *e) {
151         return static_cast<ScriptEngine *>(e)->p;
152     }
153
154     QDeclarativeEngine *qmlengine;
155
156     QMutex m_lock;
157     QWaitCondition m_wait;
158
159     struct WorkerScript {
160         WorkerScript();
161
162         int id;
163         QUrl source;
164         bool initialized;
165         QDeclarativeWorkerScript *owner;
166         QScriptValue object;
167
168         QScriptValue callback;
169     };
170
171     QHash<int, WorkerScript *> workers;
172     QScriptValue getWorker(int);
173
174     int m_nextId;
175
176     static QVariant scriptValueToVariant(const QScriptValue &);
177     static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *);
178
179     static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine);
180     static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine);
181
182 signals:
183     void stopThread();
184
185 protected:
186     virtual bool event(QEvent *);
187
188 private:
189     void processMessage(int, const QVariant &);
190     void processLoad(int, const QUrl &);
191     void reportScriptException(WorkerScript *);
192 };
193
194 QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
195 : workerEngine(0), qmlengine(engine), m_nextId(0)
196 {
197 }
198
199 QScriptValue QDeclarativeWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine)
200 {
201     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
202
203     int id = ctxt->thisObject().data().toVariant().toInt();
204
205     WorkerScript *script = p->workers.value(id);
206     if (!script)
207         return engine->undefinedValue();
208
209     if (ctxt->argumentCount() >= 1) 
210         script->callback = ctxt->argument(0);
211
212     return script->callback;
213 }
214
215 QScriptValue QDeclarativeWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine)
216 {
217     if (!ctxt->argumentCount())
218         return engine->undefinedValue();
219
220     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
221
222     int id = ctxt->thisObject().data().toVariant().toInt();
223
224     WorkerScript *script = p->workers.value(id);
225     if (!script)
226         return engine->undefinedValue();
227
228     QMutexLocker(&p->m_lock);
229
230     if (script->owner)
231         QCoreApplication::postEvent(script->owner,
232                                     new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0))));
233
234     return engine->undefinedValue();
235 }
236
237 QScriptValue QDeclarativeWorkerScriptEnginePrivate::getWorker(int id)
238 {
239     QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id);
240
241     if (iter == workers.end())
242         return workerEngine->nullValue();
243
244     WorkerScript *script = *iter;
245     if (!script->initialized) {
246
247         script->initialized = true;
248         script->object = workerEngine->newObject();
249
250         QScriptValue api = workerEngine->newObject();
251         api.setData(script->id);
252
253         api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage),
254                         QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
255         api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage));
256
257         script->object.setProperty(QLatin1String("WorkerScript"), api);
258     }
259
260     return script->object;
261 }
262
263 bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
264 {
265     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
266         WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
267         processMessage(workerEvent->workerId(), workerEvent->data());
268         return true;
269     } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
270         WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
271         processLoad(workerEvent->workerId(), workerEvent->url());
272         return true;
273     } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
274         emit stopThread();
275         return true;
276     } else {
277         return QObject::event(event);
278     }
279 }
280
281 void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data)
282 {
283     WorkerScript *script = workers.value(id);
284     if (!script)
285         return;
286
287     if (script->callback.isFunction()) {
288         QScriptValue args = workerEngine->newArray(1);
289         args.setProperty(0, variantToScriptValue(data, workerEngine));
290
291         script->callback.call(script->object, args);
292
293         if (workerEngine->hasUncaughtException()) {
294             reportScriptException(script);
295             workerEngine->clearExceptions();
296         }
297     }
298 }
299
300 void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
301 {
302     if (url.isRelative())
303         return;
304
305     QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
306
307     QFile f(fileName);
308     if (f.open(QIODevice::ReadOnly)) {
309         QByteArray data = f.readAll();
310         QString sourceCode = QString::fromUtf8(data);
311
312         QScriptValue activation = getWorker(id);
313
314         QScriptContext *ctxt = QScriptDeclarativeClass::pushCleanContext(workerEngine);
315         QScriptValue urlContext = workerEngine->newObject();
316         urlContext.setData(QScriptValue(workerEngine, url.toString()));
317         ctxt->pushScope(urlContext);
318         ctxt->pushScope(activation);
319         ctxt->setActivationObject(activation);
320         QDeclarativeScriptParser::extractPragmas(sourceCode);
321
322         workerEngine->baseUrl = url;
323         workerEngine->evaluate(sourceCode);
324
325         WorkerScript *script = workers.value(id);
326         if (script) {
327             script->source = url;
328             if (workerEngine->hasUncaughtException()) {
329                 reportScriptException(script);
330                 workerEngine->clearExceptions();
331             }
332         }
333
334         workerEngine->popContext();
335     } else {
336         qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
337     }
338 }
339
340 void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script)
341 {
342     if (!script || !workerEngine->hasUncaughtException())
343         return;
344
345     QDeclarativeError error;
346     QDeclarativeExpressionPrivate::exceptionToError(workerEngine, error);
347     error.setUrl(script->source);
348
349     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine);
350
351     QMutexLocker(&p->m_lock);
352     if (script->owner)
353         QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
354 }
355
356 QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value)
357 {
358     if (value.isBool()) {
359         return QVariant(value.toBool());
360     } else if (value.isString()) {
361         return QVariant(value.toString());
362     } else if (value.isNumber()) {
363         return QVariant((qreal)value.toNumber());
364     } else if (value.isDate()) {
365         return QVariant(value.toDateTime());
366 #ifndef QT_NO_REGEXP
367     } else if (value.isRegExp()) {
368         return QVariant(value.toRegExp());
369 #endif
370     } else if (value.isArray()) {
371         QVariantList list;
372
373         quint32 length = (quint32)value.property(QLatin1String("length")).toNumber();
374
375         for (quint32 ii = 0; ii < length; ++ii) {
376             QVariant v = scriptValueToVariant(value.property(ii));
377             list << v;
378         }
379
380         return QVariant(list);
381     } else if (value.isQObject()) {
382         QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject());
383         if (lm) {
384             QDeclarativeListModelWorkerAgent *agent = lm->agent();
385             if (agent) {
386                 QDeclarativeListModelWorkerAgent::VariantRef v(agent);
387                 return QVariant::fromValue(v);
388             } else {
389                 return QVariant();
390             }
391         } else {
392             // No other QObject's are allowed to be sent
393             return QVariant();
394         }
395     } else if (value.isObject()) {
396         QVariantHash hash;
397
398         QScriptValueIterator iter(value);
399
400         while (iter.hasNext()) {
401             iter.next();
402             hash.insert(iter.name(), scriptValueToVariant(iter.value()));
403         }
404
405         return QVariant(hash);
406     }
407
408     return QVariant();
409
410 }
411
412 QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine)
413 {
414     if (value.userType() == QVariant::Bool) {
415         return QScriptValue(value.toBool());
416     } else if (value.userType() == QVariant::String) {
417         return QScriptValue(value.toString());
418     } else if (value.userType() == QMetaType::QReal) {
419         return QScriptValue(value.toReal());
420     } else if (value.userType() == QVariant::DateTime) {
421         return engine->newDate(value.toDateTime());
422 #ifndef QT_NO_REGEXP
423     } else if (value.userType() == QVariant::RegExp) {
424         return engine->newRegExp(value.toRegExp());
425 #endif
426     } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) {
427         QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value);
428         if (vr.a->scriptEngine() == 0)
429             vr.a->setScriptEngine(engine);
430         else if (vr.a->scriptEngine() != engine)
431             return engine->nullValue();
432         QScriptValue o = engine->newQObject(vr.a);
433         o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc
434         return o;
435     } else if (value.userType() == QMetaType::QVariantList) {
436         QVariantList list = qvariant_cast<QVariantList>(value);
437         QScriptValue rv = engine->newArray(list.count());
438
439         for (quint32 ii = 0; ii < quint32(list.count()); ++ii)
440             rv.setProperty(ii, variantToScriptValue(list.at(ii), engine));
441
442         return rv;
443     } else if (value.userType() == QMetaType::QVariantHash) {
444
445         QVariantHash hash = qvariant_cast<QVariantHash>(value);
446
447         QScriptValue rv = engine->newObject();
448
449         for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter)
450             rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine));
451
452         return rv;
453     } else {
454         return engine->nullValue();
455     }
456 }
457
458 WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data)
459 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
460 {
461 }
462
463 WorkerDataEvent::~WorkerDataEvent()
464 {
465 }
466
467 int WorkerDataEvent::workerId() const
468 {
469     return m_id;
470 }
471
472 QVariant WorkerDataEvent::data() const
473 {
474     return m_data;
475 }
476
477 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
478 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
479 {
480 }
481
482 int WorkerLoadEvent::workerId() const
483 {
484     return m_id;
485 }
486
487 QUrl WorkerLoadEvent::url() const
488 {
489     return m_url;
490 }
491
492 WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
493 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
494 {
495 }
496
497 int WorkerRemoveEvent::workerId() const
498 {
499     return m_id;
500 }
501
502 WorkerErrorEvent::WorkerErrorEvent(const QDeclarativeError &error)
503 : QEvent((QEvent::Type)WorkerError), m_error(error)
504 {
505 }
506
507 QDeclarativeError WorkerErrorEvent::error() const
508 {
509     return m_error;
510 }
511
512 QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent)
513 : QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent))
514 {
515     d->m_lock.lock();
516     connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
517     start(QThread::IdlePriority);
518     d->m_wait.wait(&d->m_lock);
519     d->moveToThread(this);
520     d->m_lock.unlock();
521 }
522
523 QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine()
524 {
525     d->m_lock.lock();
526     qDeleteAll(d->workers);
527     d->workers.clear();
528     QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent));
529     d->m_lock.unlock();
530
531     wait();
532     d->deleteLater();
533 }
534
535 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
536 : id(-1), initialized(false), owner(0)
537 {
538 }
539
540 int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
541 {
542     QDeclarativeWorkerScriptEnginePrivate::WorkerScript *script = new QDeclarativeWorkerScriptEnginePrivate::WorkerScript;
543     script->id = d->m_nextId++;
544     script->owner = owner;
545
546     d->m_lock.lock();
547     d->workers.insert(script->id, script);
548     d->m_lock.unlock();
549
550     return script->id;
551 }
552
553 void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id)
554 {
555     QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
556 }
557
558 void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url)
559 {
560     QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
561 }
562
563 void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QVariant &data)
564 {
565     QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
566 }
567
568 void QDeclarativeWorkerScriptEngine::run()
569 {
570     d->m_lock.lock();
571
572     d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::ScriptEngine(d);
573
574     d->m_wait.wakeAll();
575
576     d->m_lock.unlock();
577
578     exec();
579
580     delete d->workerEngine; d->workerEngine = 0;
581 }
582
583
584 /*!
585     \qmlclass WorkerScript QDeclarativeWorkerScript
586     \ingroup qml-utility-elements
587     \brief The WorkerScript element enables the use of threads in QML.
588
589     Use WorkerScript to run operations in a new thread.
590     This is useful for running operations in the background so
591     that the main GUI thread is not blocked.
592
593     Messages can be passed between the new thread and the parent thread
594     using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
595
596     An example:
597
598     \snippet doc/src/snippets/declarative/workerscript.qml 0
599
600     The above worker script specifies a JavaScript file, "script.js", that handles
601     the operations to be performed in the new thread. Here is \c script.js:
602
603     \quotefile doc/src/snippets/declarative/script.js
604
605     When the user clicks anywhere within the rectangle, \c sendMessage() is
606     called, triggering the \tt WorkerScript.onMessage() handler in
607     \tt script.js. This in turn sends a reply message that is then received
608     by the \tt onMessage() handler of \tt myWorker.
609
610
611     \section3 Restrictions
612
613     Since the \c WorkerScript.onMessage() function is run in a separate thread, the
614     JavaScript file is evaluated in a context separate from the main QML engine. This means
615     that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
616     in the above example cannot access the properties, methods or other attributes
617     of the QML item, nor can it access any context properties set on the QML object
618     through QDeclarativeContext.
619
620     Additionally, there are restrictions on the types of values that can be passed to and
621     from the worker script. See the sendMessage() documentation for details.
622
623     \sa {declarative/threading/workerscript}{WorkerScript example},
624         {declarative/threading/threadedlistmodel}{Threaded ListModel example}
625 */
626 QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent)
627 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
628 {
629 }
630
631 QDeclarativeWorkerScript::~QDeclarativeWorkerScript()
632 {
633     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
634 }
635
636 /*!
637     \qmlproperty url WorkerScript::source
638
639     This holds the url of the JavaScript file that implements the
640     \tt WorkerScript.onMessage() handler for threaded operations.
641 */
642 QUrl QDeclarativeWorkerScript::source() const
643 {
644     return m_source;
645 }
646
647 void QDeclarativeWorkerScript::setSource(const QUrl &source)
648 {
649     if (m_source == source)
650         return;
651
652     m_source = source;
653
654     if (engine())
655         m_engine->executeUrl(m_scriptId, m_source);
656
657     emit sourceChanged();
658 }
659
660 /*!
661     \qmlmethod WorkerScript::sendMessage(jsobject message)
662
663     Sends the given \a message to a worker script handler in another
664     thread. The other worker script handler can receive this message
665     through the onMessage() handler.
666
667     The \c message object may only contain values of the following
668     types:
669
670     \list
671     \o boolean, number, string
672     \o JavaScript objects and arrays
673     \o ListModel objects (any other type of QObject* is not allowed)
674     \endlist
675
676     All objects and arrays are copied to the \c message. With the exception
677     of ListModel objects, any modifications by the other thread to an object
678     passed in \c message will not be reflected in the original object.
679 */
680 void QDeclarativeWorkerScript::sendMessage(const QScriptValue &message)
681 {
682     if (!engine()) {
683         qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
684         return;
685     }
686
687     m_engine->sendMessage(m_scriptId, QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(message));
688 }
689
690 void QDeclarativeWorkerScript::classBegin()
691 {
692     m_componentComplete = false;
693 }
694
695 QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine()
696 {
697     if (m_engine) return m_engine;
698     if (m_componentComplete) {
699         QDeclarativeEngine *engine = qmlEngine(this);
700         if (!engine) {
701             qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set");
702             return 0;
703         }
704
705         m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine();
706         m_scriptId = m_engine->registerWorkerScript(this);
707
708         if (m_source.isValid())
709             m_engine->executeUrl(m_scriptId, m_source);
710
711         return m_engine;
712     }
713     return 0;
714 }
715
716 void QDeclarativeWorkerScript::componentComplete()
717 {
718     m_componentComplete = true;
719     engine(); // Get it started now.
720 }
721
722 /*!
723     \qmlsignal WorkerScript::onMessage(jsobject msg)
724
725     This handler is called when a message \a msg is received from a worker
726     script in another thread through a call to sendMessage().
727 */
728
729 bool QDeclarativeWorkerScript::event(QEvent *event)
730 {
731     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
732         QDeclarativeEngine *engine = qmlEngine(this);
733         if (engine) {
734             QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
735             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
736             QScriptValue value =
737                 QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine);
738             emit message(value);
739         }
740         return true;
741     } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
742         WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
743         QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error());
744         return true;
745     } else {
746         return QObject::event(event);
747     }
748 }
749
750 QT_END_NAMESPACE
751
752 #include <qdeclarativeworkerscript.moc>
753