Merge branch 'master' of git://gitorious.org/qt/qtdeclarative into api_changes
[profile/ivi/qtdeclarative.git] / src / qml / qml / qquickworkerscript.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickworkerscript_p.h"
43 #include "qquicklistmodel_p.h"
44 #include "qquicklistmodelworkeragent_p.h"
45 #include "qqmlengine_p.h"
46 #include "qqmlexpression_p.h"
47
48 #include <QtCore/qcoreevent.h>
49 #include <QtCore/qcoreapplication.h>
50 #include <QtCore/qdebug.h>
51 #include <QtQml/qjsengine.h>
52 #include <QtCore/qmutex.h>
53 #include <QtCore/qwaitcondition.h>
54 #include <QtCore/qfile.h>
55 #include <QtCore/qdatetime.h>
56 #include <QtNetwork/qnetworkaccessmanager.h>
57 #include <QtQml/qqmlinfo.h>
58 #include "qqmlnetworkaccessmanagerfactory.h"
59
60 #include <private/qv8engine_p.h>
61 #include <private/qv8worker_p.h>
62
63 QT_BEGIN_NAMESPACE
64
65 class WorkerDataEvent : public QEvent
66 {
67 public:
68     enum Type { WorkerData = QEvent::User };
69
70     WorkerDataEvent(int workerId, const QByteArray &data);
71     virtual ~WorkerDataEvent();
72
73     int workerId() const;
74     QByteArray data() const;
75
76 private:
77     int m_id;
78     QByteArray m_data;
79 };
80
81 class WorkerLoadEvent : public QEvent
82 {
83 public:
84     enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 };
85
86     WorkerLoadEvent(int workerId, const QUrl &url);
87
88     int workerId() const;
89     QUrl url() const;
90
91 private:
92     int m_id;
93     QUrl m_url;
94 };
95
96 class WorkerRemoveEvent : public QEvent
97 {
98 public:
99     enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
100
101     WorkerRemoveEvent(int workerId);
102
103     int workerId() const;
104
105 private:
106     int m_id;
107 };
108
109 class WorkerErrorEvent : public QEvent
110 {
111 public:
112     enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 };
113
114     WorkerErrorEvent(const QQmlError &error);
115
116     QQmlError error() const;
117
118 private:
119     QQmlError m_error;
120 };
121
122 class QQuickWorkerScriptEnginePrivate : public QObject
123 {
124     Q_OBJECT
125 public:
126     enum WorkerEventTypes {
127         WorkerDestroyEvent = QEvent::User + 100
128     };
129
130     QQuickWorkerScriptEnginePrivate(QQmlEngine *eng);
131
132     class WorkerEngine : public QV8Engine
133     {
134     public:
135         WorkerEngine(QQuickWorkerScriptEnginePrivate *parent);
136         ~WorkerEngine();
137
138         void init();
139         virtual QNetworkAccessManager *networkAccessManager();
140
141         QQuickWorkerScriptEnginePrivate *p;
142
143         v8::Local<v8::Function> sendFunction(int id);
144         void callOnMessage(v8::Handle<v8::Object> object, v8::Handle<v8::Value> arg);
145     private:
146         v8::Persistent<v8::Function> onmessage;
147         v8::Persistent<v8::Function> createsend;
148         QNetworkAccessManager *accessManager;
149     };
150
151     WorkerEngine *workerEngine;
152     static QQuickWorkerScriptEnginePrivate *get(QV8Engine *e) {
153         return static_cast<WorkerEngine *>(e)->p;
154     }
155
156     QQmlEngine *qmlengine;
157
158     QMutex m_lock;
159     QWaitCondition m_wait;
160
161     struct WorkerScript {
162         WorkerScript();
163         ~WorkerScript();
164
165         int id;
166         QUrl source;
167         bool initialized;
168         QQuickWorkerScript *owner;
169         v8::Persistent<v8::Object> object;
170     };
171
172     QHash<int, WorkerScript *> workers;
173     v8::Handle<v8::Object> getWorker(WorkerScript *);
174
175     int m_nextId;
176
177     static v8::Handle<v8::Value> sendMessage(const v8::Arguments &args);
178
179 signals:
180     void stopThread();
181
182 protected:
183     virtual bool event(QEvent *);
184
185 private:
186     void processMessage(int, const QByteArray &);
187     void processLoad(int, const QUrl &);
188     void reportScriptException(WorkerScript *, const QQmlError &error);
189 };
190
191 QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent) 
192 : QV8Engine(0), p(parent), accessManager(0)
193 {
194 }
195
196 QQuickWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() 
197
198     qPersistentDispose(createsend);
199     qPersistentDispose(onmessage);
200     delete accessManager; 
201 }
202
203 void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
204 {
205     initQmlGlobalObject();
206 #define CALL_ONMESSAGE_SCRIPT \
207     "(function(object, message) { "\
208         "var isfunction = false; "\
209         "try { "\
210             "isfunction = object.WorkerScript.onMessage instanceof Function; "\
211         "} catch (e) {}" \
212         "if (isfunction) "\
213             "object.WorkerScript.onMessage(message); "\
214     "})"
215
216 #define SEND_MESSAGE_CREATE_SCRIPT \
217     "(function(method, engine) { "\
218         "return (function(id) { "\
219             "return (function(message) { "\
220                 "if (arguments.length) method(engine, id, message); "\
221             "}); "\
222         "}); "\
223     "})"
224
225     v8::HandleScope handle_scope;
226     v8::Context::Scope scope(context());
227
228     {
229     v8::Local<v8::Script> onmessagescript = v8::Script::New(v8::String::New(CALL_ONMESSAGE_SCRIPT));
230     onmessage = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
231     }
232     {
233     v8::Local<v8::Script> createsendscript = v8::Script::New(v8::String::New(SEND_MESSAGE_CREATE_SCRIPT));
234     v8::Local<v8::Function> createsendconstructor = v8::Local<v8::Function>::Cast(createsendscript->Run());
235
236     v8::Handle<v8::Value> args[] = { 
237         V8FUNCTION(QQuickWorkerScriptEnginePrivate::sendMessage, this)
238     };
239     v8::Local<v8::Value> createsendvalue = createsendconstructor->Call(global(), 1, args);
240     
241     createsend = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(createsendvalue));
242     }
243 }
244
245 // Requires handle and context scope
246 v8::Local<v8::Function> QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(int id)
247 {
248     v8::Handle<v8::Value> args[] = { v8::Integer::New(id) };
249     return v8::Local<v8::Function>::Cast(createsend->Call(global(), 1, args));
250 }
251
252 // Requires handle and context scope
253 void QQuickWorkerScriptEnginePrivate::WorkerEngine::callOnMessage(v8::Handle<v8::Object> object, 
254                                                                         v8::Handle<v8::Value> arg)
255 {
256     v8::Handle<v8::Value> args[] = { object, arg };
257     onmessage->Call(global(), 2, args);
258 }
259
260 QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager() 
261 {
262     if (!accessManager) {
263         if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
264             accessManager = p->qmlengine->networkAccessManagerFactory()->create(p);
265         } else {
266             accessManager = new QNetworkAccessManager(p);
267         }
268     }
269     return accessManager;
270 }
271
272 QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *engine)
273 : workerEngine(0), qmlengine(engine), m_nextId(0)
274 {
275 }
276
277 v8::Handle<v8::Value> QQuickWorkerScriptEnginePrivate::sendMessage(const v8::Arguments &args)
278 {
279     WorkerEngine *engine = (WorkerEngine*)V8ENGINE();
280
281     int id = args[1]->Int32Value();
282
283     QByteArray data = QV8Worker::serialize(args[2], engine);
284
285     QMutexLocker(&engine->p->m_lock);
286     WorkerScript *script = engine->p->workers.value(id);
287     if (!script)
288         return v8::Undefined();
289
290     if (script->owner)
291         QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
292
293     return v8::Undefined();
294 }
295
296 // Requires handle scope and context scope
297 v8::Handle<v8::Object> QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *script)
298 {
299     if (!script->initialized) {
300         script->initialized = true;
301
302         script->object = qPersistentNew<v8::Object>(workerEngine->contextWrapper()->urlScope(script->source));
303
304         workerEngine->contextWrapper()->setReadOnly(script->object, false);
305
306         v8::Local<v8::Object> api = v8::Object::New();
307         api->Set(v8::String::New("sendMessage"), workerEngine->sendFunction(script->id));
308
309         script->object->Set(v8::String::New("WorkerScript"), api);
310
311         workerEngine->contextWrapper()->setReadOnly(script->object, true);
312     }
313
314     return script->object;
315 }
316
317 bool QQuickWorkerScriptEnginePrivate::event(QEvent *event)
318 {
319     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
320         WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
321         processMessage(workerEvent->workerId(), workerEvent->data());
322         return true;
323     } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
324         WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
325         processLoad(workerEvent->workerId(), workerEvent->url());
326         return true;
327     } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
328         emit stopThread();
329         return true;
330     } else if (event->type() == (QEvent::Type)WorkerRemoveEvent::WorkerRemove) {
331         WorkerRemoveEvent *workerEvent = static_cast<WorkerRemoveEvent *>(event);
332         workers.remove(workerEvent->workerId());
333         return true;
334     } else {
335         return QObject::event(event);
336     }
337 }
338
339 void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
340 {
341     WorkerScript *script = workers.value(id);
342     if (!script)
343         return;
344
345     v8::HandleScope handle_scope;
346     v8::Context::Scope scope(workerEngine->context());
347
348     v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
349
350     v8::TryCatch tc;
351     workerEngine->callOnMessage(script->object, value);
352
353     if (tc.HasCaught()) {
354         QQmlError error;
355         QQmlExpressionPrivate::exceptionToError(tc.Message(), error);
356         reportScriptException(script, error);
357     }
358 }
359
360 void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
361 {
362     if (url.isRelative())
363         return;
364
365     QString fileName = QQmlEnginePrivate::urlToLocalFileOrQrc(url);
366
367     QFile f(fileName);
368     if (f.open(QIODevice::ReadOnly)) {
369         QByteArray data = f.readAll();
370         QString sourceCode = QString::fromUtf8(data);
371         QQmlScript::Parser::extractPragmas(sourceCode);
372
373         v8::HandleScope handle_scope;
374         v8::Context::Scope scope(workerEngine->context());
375
376         WorkerScript *script = workers.value(id);
377         if (!script)
378             return;
379         script->source = url;
380         v8::Handle<v8::Object> activation = getWorker(script);
381         if (activation.IsEmpty())
382             return;
383
384         // XXX ???
385         // workerEngine->baseUrl = url;
386
387         v8::TryCatch tc;
388         v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
389
390         if (!tc.HasCaught()) 
391             program->Run(activation);
392         
393         if (tc.HasCaught()) {
394             QQmlError error;
395             QQmlExpressionPrivate::exceptionToError(tc.Message(), error);
396             reportScriptException(script, error);
397         }
398     } else {
399         qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
400     }
401 }
402
403 void QQuickWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script, 
404                                                                   const QQmlError &error)
405 {
406     QQuickWorkerScriptEnginePrivate *p = QQuickWorkerScriptEnginePrivate::get(workerEngine);
407
408     QMutexLocker(&p->m_lock);
409     if (script->owner)
410         QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
411 }
412
413 WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
414 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
415 {
416 }
417
418 WorkerDataEvent::~WorkerDataEvent()
419 {
420 }
421
422 int WorkerDataEvent::workerId() const
423 {
424     return m_id;
425 }
426
427 QByteArray WorkerDataEvent::data() const
428 {
429     return m_data;
430 }
431
432 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
433 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
434 {
435 }
436
437 int WorkerLoadEvent::workerId() const
438 {
439     return m_id;
440 }
441
442 QUrl WorkerLoadEvent::url() const
443 {
444     return m_url;
445 }
446
447 WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
448 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
449 {
450 }
451
452 int WorkerRemoveEvent::workerId() const
453 {
454     return m_id;
455 }
456
457 WorkerErrorEvent::WorkerErrorEvent(const QQmlError &error)
458 : QEvent((QEvent::Type)WorkerError), m_error(error)
459 {
460 }
461
462 QQmlError WorkerErrorEvent::error() const
463 {
464     return m_error;
465 }
466
467 QQuickWorkerScriptEngine::QQuickWorkerScriptEngine(QQmlEngine *parent)
468 : QThread(parent), d(new QQuickWorkerScriptEnginePrivate(parent))
469 {
470     d->m_lock.lock();
471     connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
472     start(QThread::LowestPriority);
473     d->m_wait.wait(&d->m_lock);
474     d->moveToThread(this);
475     d->m_lock.unlock();
476 }
477
478 QQuickWorkerScriptEngine::~QQuickWorkerScriptEngine()
479 {
480     d->m_lock.lock();
481     QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QQuickWorkerScriptEnginePrivate::WorkerDestroyEvent));
482     d->m_lock.unlock();
483
484     //We have to force to cleanup the main thread's event queue here
485     //to make sure the main GUI release all pending locks/wait conditions which
486     //some worker script/agent are waiting for (QQuickListModelWorkerAgent::sync() for example).
487     QCoreApplication::processEvents();
488     wait();
489     d->deleteLater();
490 }
491
492 QQuickWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
493 : id(-1), initialized(false), owner(0)
494 {
495 }
496
497 QQuickWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
498 {
499     qPersistentDispose(object);
500 }
501
502 int QQuickWorkerScriptEngine::registerWorkerScript(QQuickWorkerScript *owner)
503 {
504     typedef QQuickWorkerScriptEnginePrivate::WorkerScript WorkerScript;
505     WorkerScript *script = new WorkerScript;
506
507     script->id = d->m_nextId++;
508     script->owner = owner;
509
510     d->m_lock.lock();
511     d->workers.insert(script->id, script);
512     d->m_lock.unlock();
513
514     return script->id;
515 }
516
517 void QQuickWorkerScriptEngine::removeWorkerScript(int id)
518 {
519     QQuickWorkerScriptEnginePrivate::WorkerScript* script = d->workers.value(id);
520     if (script) {
521         script->owner = 0;
522         QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
523     }
524 }
525
526 void QQuickWorkerScriptEngine::executeUrl(int id, const QUrl &url)
527 {
528     QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
529 }
530
531 void QQuickWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
532 {
533     QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
534 }
535
536 void QQuickWorkerScriptEngine::run()
537 {
538     d->m_lock.lock();
539
540     d->workerEngine = new QQuickWorkerScriptEnginePrivate::WorkerEngine(d);
541     d->workerEngine->init();
542
543     d->m_wait.wakeAll();
544
545     d->m_lock.unlock();
546
547     exec();
548
549     qDeleteAll(d->workers);
550     d->workers.clear();
551
552     delete d->workerEngine; d->workerEngine = 0;
553 }
554
555
556 /*!
557     \qmlclass WorkerScript QQuickWorkerScript
558     \ingroup qml-utility-elements
559     \brief The WorkerScript element enables the use of threads in QML.
560
561     Use WorkerScript to run operations in a new thread.
562     This is useful for running operations in the background so
563     that the main GUI thread is not blocked.
564
565     Messages can be passed between the new thread and the parent thread
566     using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
567
568     An example:
569
570     \snippet doc/src/snippets/qml/workerscript.qml 0
571
572     The above worker script specifies a JavaScript file, "script.js", that handles
573     the operations to be performed in the new thread. Here is \c script.js:
574
575     \quotefile doc/src/snippets/qml/script.js
576
577     When the user clicks anywhere within the rectangle, \c sendMessage() is
578     called, triggering the \tt WorkerScript.onMessage() handler in
579     \tt script.js. This in turn sends a reply message that is then received
580     by the \tt onMessage() handler of \tt myWorker.
581
582
583     \section3 Restrictions
584
585     Since the \c WorkerScript.onMessage() function is run in a separate thread, the
586     JavaScript file is evaluated in a context separate from the main QML engine. This means
587     that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
588     in the above example cannot access the properties, methods or other attributes
589     of the QML item, nor can it access any context properties set on the QML object
590     through QQmlContext.
591
592     Additionally, there are restrictions on the types of values that can be passed to and
593     from the worker script. See the sendMessage() documentation for details.
594
595     \sa {declarative/threading/workerscript}{WorkerScript example},
596         {declarative/threading/threadedlistmodel}{Threaded ListModel example}
597 */
598 QQuickWorkerScript::QQuickWorkerScript(QObject *parent)
599 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
600 {
601 }
602
603 QQuickWorkerScript::~QQuickWorkerScript()
604 {
605     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
606 }
607
608 /*!
609     \qmlproperty url WorkerScript::source
610
611     This holds the url of the JavaScript file that implements the
612     \tt WorkerScript.onMessage() handler for threaded operations.
613 */
614 QUrl QQuickWorkerScript::source() const
615 {
616     return m_source;
617 }
618
619 void QQuickWorkerScript::setSource(const QUrl &source)
620 {
621     if (m_source == source)
622         return;
623
624     m_source = source;
625
626     if (engine())
627         m_engine->executeUrl(m_scriptId, m_source);
628
629     emit sourceChanged();
630 }
631
632 /*!
633     \qmlmethod WorkerScript::sendMessage(jsobject message)
634
635     Sends the given \a message to a worker script handler in another
636     thread. The other worker script handler can receive this message
637     through the onMessage() handler.
638
639     The \c message object may only contain values of the following
640     types:
641
642     \list
643     \o boolean, number, string
644     \o JavaScript objects and arrays
645     \o ListModel objects (any other type of QObject* is not allowed)
646     \endlist
647
648     All objects and arrays are copied to the \c message. With the exception
649     of ListModel objects, any modifications by the other thread to an object
650     passed in \c message will not be reflected in the original object.
651 */
652 void QQuickWorkerScript::sendMessage(QQmlV8Function *args)
653 {
654     if (!engine()) {
655         qWarning("QQuickWorkerScript: Attempt to send message before WorkerScript establishment");
656         return;
657     }
658
659     v8::Handle<v8::Value> argument = v8::Undefined();
660     if (args->Length() != 0) 
661         argument = (*args)[0];
662
663     m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
664 }
665
666 void QQuickWorkerScript::classBegin()
667 {
668     m_componentComplete = false;
669 }
670
671 QQuickWorkerScriptEngine *QQuickWorkerScript::engine()
672 {
673     if (m_engine) return m_engine;
674     if (m_componentComplete) {
675         QQmlEngine *engine = qmlEngine(this);
676         if (!engine) {
677             qWarning("QQuickWorkerScript: engine() called without qmlEngine() set");
678             return 0;
679         }
680
681         m_engine = QQmlEnginePrivate::get(engine)->getWorkerScriptEngine();
682         m_scriptId = m_engine->registerWorkerScript(this);
683
684         if (m_source.isValid())
685             m_engine->executeUrl(m_scriptId, m_source);
686
687         return m_engine;
688     }
689     return 0;
690 }
691
692 void QQuickWorkerScript::componentComplete()
693 {
694     m_componentComplete = true;
695     engine(); // Get it started now.
696 }
697
698 /*!
699     \qmlsignal WorkerScript::onMessage(jsobject msg)
700
701     This handler is called when a message \a msg is received from a worker
702     script in another thread through a call to sendMessage().
703 */
704
705 bool QQuickWorkerScript::event(QEvent *event)
706 {
707     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
708         QQmlEngine *engine = qmlEngine(this);
709         if (engine) {
710             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
711             QV8Engine *v8engine = QQmlEnginePrivate::get(engine)->v8engine();
712             v8::HandleScope handle_scope;
713             v8::Context::Scope scope(v8engine->context());
714             v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
715             emit message(QQmlV8Handle::fromHandle(value));
716         }
717         return true;
718     } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
719         WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
720         QQmlEnginePrivate::warning(qmlEngine(this), workerEvent->error());
721         return true;
722     } else {
723         return QObject::event(event);
724     }
725 }
726
727 QT_END_NAMESPACE
728
729 #include <qquickworkerscript.moc>
730