bc7e645becbcc1019198860901939b398fcc7239
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeworkerscript.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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     //We have to force to cleanup the main thread's event queue here
482     //to make sure the main GUI release all pending locks/wait conditions which
483     //some worker script/agent are waiting for (QDeclarativeListModelWorkerAgent::sync() for example).
484     QCoreApplication::processEvents();
485     wait();
486     d->deleteLater();
487 }
488
489 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
490 : id(-1), initialized(false), owner(0)
491 {
492 }
493
494 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
495 {
496     qPersistentDispose(object);
497 }
498
499 int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
500 {
501     typedef QDeclarativeWorkerScriptEnginePrivate::WorkerScript WorkerScript;
502     WorkerScript *script = new WorkerScript;
503
504     script->id = d->m_nextId++;
505     script->owner = owner;
506
507     d->m_lock.lock();
508     d->workers.insert(script->id, script);
509     d->m_lock.unlock();
510
511     return script->id;
512 }
513
514 void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id)
515 {
516     QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
517 }
518
519 void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url)
520 {
521     QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
522 }
523
524 void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
525 {
526     QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
527 }
528
529 void QDeclarativeWorkerScriptEngine::run()
530 {
531     d->m_lock.lock();
532
533     d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::WorkerEngine(d);
534     d->workerEngine->init();
535
536     d->m_wait.wakeAll();
537
538     d->m_lock.unlock();
539
540     exec();
541
542     qDeleteAll(d->workers);
543     d->workers.clear();
544
545     delete d->workerEngine; d->workerEngine = 0;
546 }
547
548
549 /*!
550     \qmlclass WorkerScript QDeclarativeWorkerScript
551     \ingroup qml-utility-elements
552     \brief The WorkerScript element enables the use of threads in QML.
553
554     Use WorkerScript to run operations in a new thread.
555     This is useful for running operations in the background so
556     that the main GUI thread is not blocked.
557
558     Messages can be passed between the new thread and the parent thread
559     using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
560
561     An example:
562
563     \snippet doc/src/snippets/declarative/workerscript.qml 0
564
565     The above worker script specifies a JavaScript file, "script.js", that handles
566     the operations to be performed in the new thread. Here is \c script.js:
567
568     \quotefile doc/src/snippets/declarative/script.js
569
570     When the user clicks anywhere within the rectangle, \c sendMessage() is
571     called, triggering the \tt WorkerScript.onMessage() handler in
572     \tt script.js. This in turn sends a reply message that is then received
573     by the \tt onMessage() handler of \tt myWorker.
574
575
576     \section3 Restrictions
577
578     Since the \c WorkerScript.onMessage() function is run in a separate thread, the
579     JavaScript file is evaluated in a context separate from the main QML engine. This means
580     that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
581     in the above example cannot access the properties, methods or other attributes
582     of the QML item, nor can it access any context properties set on the QML object
583     through QDeclarativeContext.
584
585     Additionally, there are restrictions on the types of values that can be passed to and
586     from the worker script. See the sendMessage() documentation for details.
587
588     \sa {declarative/threading/workerscript}{WorkerScript example},
589         {declarative/threading/threadedlistmodel}{Threaded ListModel example}
590 */
591 QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent)
592 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
593 {
594 }
595
596 QDeclarativeWorkerScript::~QDeclarativeWorkerScript()
597 {
598     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
599 }
600
601 /*!
602     \qmlproperty url WorkerScript::source
603
604     This holds the url of the JavaScript file that implements the
605     \tt WorkerScript.onMessage() handler for threaded operations.
606 */
607 QUrl QDeclarativeWorkerScript::source() const
608 {
609     return m_source;
610 }
611
612 void QDeclarativeWorkerScript::setSource(const QUrl &source)
613 {
614     if (m_source == source)
615         return;
616
617     m_source = source;
618
619     if (engine())
620         m_engine->executeUrl(m_scriptId, m_source);
621
622     emit sourceChanged();
623 }
624
625 /*!
626     \qmlmethod WorkerScript::sendMessage(jsobject message)
627
628     Sends the given \a message to a worker script handler in another
629     thread. The other worker script handler can receive this message
630     through the onMessage() handler.
631
632     The \c message object may only contain values of the following
633     types:
634
635     \list
636     \o boolean, number, string
637     \o JavaScript objects and arrays
638     \o ListModel objects (any other type of QObject* is not allowed)
639     \endlist
640
641     All objects and arrays are copied to the \c message. With the exception
642     of ListModel objects, any modifications by the other thread to an object
643     passed in \c message will not be reflected in the original object.
644 */
645 void QDeclarativeWorkerScript::sendMessage(QDeclarativeV8Function *args)
646 {
647     if (!engine()) {
648         qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
649         return;
650     }
651
652     v8::Handle<v8::Value> argument = v8::Undefined();
653     if (args->Length() != 0) 
654         argument = (*args)[0];
655
656     m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
657 }
658
659 void QDeclarativeWorkerScript::classBegin()
660 {
661     m_componentComplete = false;
662 }
663
664 QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine()
665 {
666     if (m_engine) return m_engine;
667     if (m_componentComplete) {
668         QDeclarativeEngine *engine = qmlEngine(this);
669         if (!engine) {
670             qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set");
671             return 0;
672         }
673
674         m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine();
675         m_scriptId = m_engine->registerWorkerScript(this);
676
677         if (m_source.isValid())
678             m_engine->executeUrl(m_scriptId, m_source);
679
680         return m_engine;
681     }
682     return 0;
683 }
684
685 void QDeclarativeWorkerScript::componentComplete()
686 {
687     m_componentComplete = true;
688     engine(); // Get it started now.
689 }
690
691 /*!
692     \qmlsignal WorkerScript::onMessage(jsobject msg)
693
694     This handler is called when a message \a msg is received from a worker
695     script in another thread through a call to sendMessage().
696 */
697
698 bool QDeclarativeWorkerScript::event(QEvent *event)
699 {
700     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
701         QDeclarativeEngine *engine = qmlEngine(this);
702         if (engine) {
703             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
704             QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine();
705             v8::HandleScope handle_scope;
706             v8::Context::Scope scope(v8engine->context());
707             v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
708             emit message(QDeclarativeV8Handle::fromHandle(value));
709         }
710         return true;
711     } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
712         WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
713         QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error());
714         return true;
715     } else {
716         return QObject::event(event);
717     }
718 }
719
720 QT_END_NAMESPACE
721
722 #include <qdeclarativeworkerscript.moc>
723