4e2bcdda01b1c2e02fa52df0e3b9d2ef5da3b0fe
[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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativeworkerscript_p.h"
43 #include "qdeclarativelistmodel_p.h"
44 #include "qdeclarativelistmodelworkeragent_p.h"
45 #include "qdeclarativeengine_p.h"
46 #include "qdeclarativeexpression_p.h"
47
48 #include <QtCore/qcoreevent.h>
49 #include <QtCore/qcoreapplication.h>
50 #include <QtCore/qdebug.h>
51 #include <QtDeclarative/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 <QtDeclarative/qdeclarativeinfo.h>
58 #include "qdeclarativenetworkaccessmanagerfactory.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 QDeclarativeError &error);
115
116     QDeclarativeError error() const;
117
118 private:
119     QDeclarativeError m_error;
120 };
121
122 class QDeclarativeWorkerScriptEnginePrivate : public QObject
123 {
124     Q_OBJECT
125 public:
126     enum WorkerEventTypes {
127         WorkerDestroyEvent = QEvent::User + 100
128     };
129
130     QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng);
131
132     class WorkerEngine : public QV8Engine
133     {
134     public:
135         WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent);
136         ~WorkerEngine();
137
138         void init();
139         virtual QNetworkAccessManager *networkAccessManager();
140
141         QDeclarativeWorkerScriptEnginePrivate *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 QDeclarativeWorkerScriptEnginePrivate *get(QV8Engine *e) {
153         return static_cast<WorkerEngine *>(e)->p;
154     }
155
156     QDeclarativeEngine *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         QDeclarativeWorkerScript *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 QDeclarativeError &error);
189 };
190
191 QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent) 
192 : QV8Engine(0), p(parent), accessManager(0)
193 {
194 }
195
196 QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() 
197
198     qPersistentDispose(createsend);
199     qPersistentDispose(onmessage);
200     delete accessManager; 
201 }
202
203 void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
204 {
205     initDeclarativeGlobalObject();
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(QDeclarativeWorkerScriptEnginePrivate::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> QDeclarativeWorkerScriptEnginePrivate::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 QDeclarativeWorkerScriptEnginePrivate::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 *QDeclarativeWorkerScriptEnginePrivate::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 QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
273 : workerEngine(0), qmlengine(engine), m_nextId(0)
274 {
275 }
276
277 v8::Handle<v8::Value> QDeclarativeWorkerScriptEnginePrivate::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> QDeclarativeWorkerScriptEnginePrivate::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 QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
318 {
319     // XXX must handle remove request
320     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
321         WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
322         processMessage(workerEvent->workerId(), workerEvent->data());
323         return true;
324     } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
325         WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
326         processLoad(workerEvent->workerId(), workerEvent->url());
327         return true;
328     } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
329         emit stopThread();
330         return true;
331     } else {
332         return QObject::event(event);
333     }
334 }
335
336 void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
337 {
338     WorkerScript *script = workers.value(id);
339     if (!script)
340         return;
341
342     v8::HandleScope handle_scope;
343     v8::Context::Scope scope(workerEngine->context());
344
345     v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
346
347     v8::TryCatch tc;
348     workerEngine->callOnMessage(script->object, value);
349
350     if (tc.HasCaught()) {
351         QDeclarativeError error;
352         QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
353         reportScriptException(script, error);
354     }
355 }
356
357 void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
358 {
359     if (url.isRelative())
360         return;
361
362     QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
363
364     QFile f(fileName);
365     if (f.open(QIODevice::ReadOnly)) {
366         QByteArray data = f.readAll();
367         QString sourceCode = QString::fromUtf8(data);
368         QDeclarativeScript::Parser::extractPragmas(sourceCode);
369
370         v8::HandleScope handle_scope;
371         v8::Context::Scope scope(workerEngine->context());
372
373         WorkerScript *script = workers.value(id);
374         if (!script)
375             return;
376         script->source = url;
377         v8::Handle<v8::Object> activation = getWorker(script);
378         if (activation.IsEmpty())
379             return;
380
381         // XXX ???
382         // workerEngine->baseUrl = url;
383
384         v8::TryCatch tc;
385         v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
386
387         if (!tc.HasCaught()) 
388             program->Run(activation);
389         
390         if (tc.HasCaught()) {
391             QDeclarativeError error;
392             QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
393             reportScriptException(script, error);
394         }
395     } else {
396         qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
397     }
398 }
399
400 void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script, 
401                                                                   const QDeclarativeError &error)
402 {
403     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine);
404
405     QMutexLocker(&p->m_lock);
406     if (script->owner)
407         QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
408 }
409
410 WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
411 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
412 {
413 }
414
415 WorkerDataEvent::~WorkerDataEvent()
416 {
417 }
418
419 int WorkerDataEvent::workerId() const
420 {
421     return m_id;
422 }
423
424 QByteArray WorkerDataEvent::data() const
425 {
426     return m_data;
427 }
428
429 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
430 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
431 {
432 }
433
434 int WorkerLoadEvent::workerId() const
435 {
436     return m_id;
437 }
438
439 QUrl WorkerLoadEvent::url() const
440 {
441     return m_url;
442 }
443
444 WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
445 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
446 {
447 }
448
449 int WorkerRemoveEvent::workerId() const
450 {
451     return m_id;
452 }
453
454 WorkerErrorEvent::WorkerErrorEvent(const QDeclarativeError &error)
455 : QEvent((QEvent::Type)WorkerError), m_error(error)
456 {
457 }
458
459 QDeclarativeError WorkerErrorEvent::error() const
460 {
461     return m_error;
462 }
463
464 QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent)
465 : QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent))
466 {
467     d->m_lock.lock();
468     connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
469     start(QThread::LowestPriority);
470     d->m_wait.wait(&d->m_lock);
471     d->moveToThread(this);
472     d->m_lock.unlock();
473 }
474
475 QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine()
476 {
477     d->m_lock.lock();
478     QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent));
479     d->m_lock.unlock();
480
481     wait();
482     d->deleteLater();
483 }
484
485 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
486 : id(-1), initialized(false), owner(0)
487 {
488 }
489
490 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
491 {
492     qPersistentDispose(object);
493 }
494
495 int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
496 {
497     typedef QDeclarativeWorkerScriptEnginePrivate::WorkerScript WorkerScript;
498     WorkerScript *script = new WorkerScript;
499
500     script->id = d->m_nextId++;
501     script->owner = owner;
502
503     d->m_lock.lock();
504     d->workers.insert(script->id, script);
505     d->m_lock.unlock();
506
507     return script->id;
508 }
509
510 void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id)
511 {
512     QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
513 }
514
515 void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url)
516 {
517     QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
518 }
519
520 void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
521 {
522     QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
523 }
524
525 void QDeclarativeWorkerScriptEngine::run()
526 {
527     d->m_lock.lock();
528
529     v8::Isolate *isolate = v8::Isolate::New(); 
530     isolate->Enter();
531
532     d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::WorkerEngine(d);
533     d->workerEngine->init();
534
535     d->m_wait.wakeAll();
536
537     d->m_lock.unlock();
538
539     exec();
540
541     qDeleteAll(d->workers);
542     d->workers.clear();
543
544     delete d->workerEngine; d->workerEngine = 0;
545     QV8GCCallback::releaseWorkerThreadGcPrologueCallbackData();
546     isolate->Exit();
547     isolate->Dispose();
548 }
549
550
551 /*!
552     \qmlclass WorkerScript QDeclarativeWorkerScript
553     \ingroup qml-utility-elements
554     \brief The WorkerScript element enables the use of threads in QML.
555
556     Use WorkerScript to run operations in a new thread.
557     This is useful for running operations in the background so
558     that the main GUI thread is not blocked.
559
560     Messages can be passed between the new thread and the parent thread
561     using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
562
563     An example:
564
565     \snippet doc/src/snippets/declarative/workerscript.qml 0
566
567     The above worker script specifies a JavaScript file, "script.js", that handles
568     the operations to be performed in the new thread. Here is \c script.js:
569
570     \quotefile doc/src/snippets/declarative/script.js
571
572     When the user clicks anywhere within the rectangle, \c sendMessage() is
573     called, triggering the \tt WorkerScript.onMessage() handler in
574     \tt script.js. This in turn sends a reply message that is then received
575     by the \tt onMessage() handler of \tt myWorker.
576
577
578     \section3 Restrictions
579
580     Since the \c WorkerScript.onMessage() function is run in a separate thread, the
581     JavaScript file is evaluated in a context separate from the main QML engine. This means
582     that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
583     in the above example cannot access the properties, methods or other attributes
584     of the QML item, nor can it access any context properties set on the QML object
585     through QDeclarativeContext.
586
587     Additionally, there are restrictions on the types of values that can be passed to and
588     from the worker script. See the sendMessage() documentation for details.
589
590     \sa {declarative/threading/workerscript}{WorkerScript example},
591         {declarative/threading/threadedlistmodel}{Threaded ListModel example}
592 */
593 QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent)
594 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
595 {
596 }
597
598 QDeclarativeWorkerScript::~QDeclarativeWorkerScript()
599 {
600     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
601 }
602
603 /*!
604     \qmlproperty url WorkerScript::source
605
606     This holds the url of the JavaScript file that implements the
607     \tt WorkerScript.onMessage() handler for threaded operations.
608 */
609 QUrl QDeclarativeWorkerScript::source() const
610 {
611     return m_source;
612 }
613
614 void QDeclarativeWorkerScript::setSource(const QUrl &source)
615 {
616     if (m_source == source)
617         return;
618
619     m_source = source;
620
621     if (engine())
622         m_engine->executeUrl(m_scriptId, m_source);
623
624     emit sourceChanged();
625 }
626
627 /*!
628     \qmlmethod WorkerScript::sendMessage(jsobject message)
629
630     Sends the given \a message to a worker script handler in another
631     thread. The other worker script handler can receive this message
632     through the onMessage() handler.
633
634     The \c message object may only contain values of the following
635     types:
636
637     \list
638     \o boolean, number, string
639     \o JavaScript objects and arrays
640     \o ListModel objects (any other type of QObject* is not allowed)
641     \endlist
642
643     All objects and arrays are copied to the \c message. With the exception
644     of ListModel objects, any modifications by the other thread to an object
645     passed in \c message will not be reflected in the original object.
646 */
647 void QDeclarativeWorkerScript::sendMessage(QDeclarativeV8Function *args)
648 {
649     if (!engine()) {
650         qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
651         return;
652     }
653
654     v8::Handle<v8::Value> argument = v8::Undefined();
655     if (args->Length() != 0) 
656         argument = (*args)[0];
657
658     m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
659 }
660
661 void QDeclarativeWorkerScript::classBegin()
662 {
663     m_componentComplete = false;
664 }
665
666 QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine()
667 {
668     if (m_engine) return m_engine;
669     if (m_componentComplete) {
670         QDeclarativeEngine *engine = qmlEngine(this);
671         if (!engine) {
672             qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set");
673             return 0;
674         }
675
676         m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine();
677         m_scriptId = m_engine->registerWorkerScript(this);
678
679         if (m_source.isValid())
680             m_engine->executeUrl(m_scriptId, m_source);
681
682         return m_engine;
683     }
684     return 0;
685 }
686
687 void QDeclarativeWorkerScript::componentComplete()
688 {
689     m_componentComplete = true;
690     engine(); // Get it started now.
691 }
692
693 /*!
694     \qmlsignal WorkerScript::onMessage(jsobject msg)
695
696     This handler is called when a message \a msg is received from a worker
697     script in another thread through a call to sendMessage().
698 */
699
700 bool QDeclarativeWorkerScript::event(QEvent *event)
701 {
702     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
703         QDeclarativeEngine *engine = qmlEngine(this);
704         if (engine) {
705             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
706             QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine();
707             v8::HandleScope handle_scope;
708             v8::Context::Scope scope(v8engine->context());
709             v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
710             emit message(QDeclarativeV8Handle::fromHandle(value));
711         }
712         return true;
713     } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
714         WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
715         QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error());
716         return true;
717     } else {
718         return QObject::event(event);
719     }
720 }
721
722 QT_END_NAMESPACE
723
724 #include <qdeclarativeworkerscript.moc>
725