ad3ca58c6c49d2b28b21476dcec285cd6d0cca73
[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 "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 #include <private/qv8engine_p.h>
62 #include <private/qv8worker_p.h>
63
64 QT_BEGIN_NAMESPACE
65
66 class WorkerDataEvent : public QEvent
67 {
68 public:
69     enum Type { WorkerData = QEvent::User };
70
71     WorkerDataEvent(int workerId, const QByteArray &data);
72     virtual ~WorkerDataEvent();
73
74     int workerId() const;
75     QByteArray data() const;
76
77 private:
78     int m_id;
79     QByteArray m_data;
80 };
81
82 class WorkerLoadEvent : public QEvent
83 {
84 public:
85     enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 };
86
87     WorkerLoadEvent(int workerId, const QUrl &url);
88
89     int workerId() const;
90     QUrl url() const;
91
92 private:
93     int m_id;
94     QUrl m_url;
95 };
96
97 class WorkerRemoveEvent : public QEvent
98 {
99 public:
100     enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
101
102     WorkerRemoveEvent(int workerId);
103
104     int workerId() const;
105
106 private:
107     int m_id;
108 };
109
110 class WorkerErrorEvent : public QEvent
111 {
112 public:
113     enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 };
114
115     WorkerErrorEvent(const QDeclarativeError &error);
116
117     QDeclarativeError error() const;
118
119 private:
120     QDeclarativeError m_error;
121 };
122
123 class QDeclarativeWorkerScriptEnginePrivate : public QObject
124 {
125     Q_OBJECT
126 public:
127     enum WorkerEventTypes {
128         WorkerDestroyEvent = QEvent::User + 100
129     };
130
131     QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng);
132
133     class WorkerEngine : public QV8Engine
134     {
135     public:
136         WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent);
137         ~WorkerEngine();
138
139         void init();
140         virtual QNetworkAccessManager *networkAccessManager();
141
142         QDeclarativeWorkerScriptEnginePrivate *p;
143
144         v8::Local<v8::Function> sendFunction(int id);
145         void callOnMessage(v8::Handle<v8::Object> object, v8::Handle<v8::Value> arg);
146     private:
147         v8::Persistent<v8::Function> onmessage;
148         v8::Persistent<v8::Function> createsend;
149         QNetworkAccessManager *accessManager;
150     };
151
152     WorkerEngine *workerEngine;
153     static QDeclarativeWorkerScriptEnginePrivate *get(QV8Engine *e) {
154         return static_cast<WorkerEngine *>(e)->p;
155     }
156
157     QDeclarativeEngine *qmlengine;
158
159     QMutex m_lock;
160     QWaitCondition m_wait;
161
162     struct WorkerScript {
163         WorkerScript();
164         ~WorkerScript();
165
166         int id;
167         QUrl source;
168         bool initialized;
169         QDeclarativeWorkerScript *owner;
170         v8::Persistent<v8::Object> object;
171     };
172
173     QHash<int, WorkerScript *> workers;
174     v8::Handle<v8::Object> getWorker(WorkerScript *);
175
176     int m_nextId;
177
178     static v8::Handle<v8::Value> sendMessage(const v8::Arguments &args);
179
180 signals:
181     void stopThread();
182
183 protected:
184     virtual bool event(QEvent *);
185
186 private:
187     void processMessage(int, const QByteArray &);
188     void processLoad(int, const QUrl &);
189     void reportScriptException(WorkerScript *, const QDeclarativeError &error);
190 };
191
192 QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent) 
193 : p(parent), accessManager(0) 
194 {
195 }
196
197 QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() 
198
199     createsend.Dispose(); createsend.Clear();
200     onmessage.Dispose(); onmessage.Clear();
201     delete accessManager; 
202 }
203
204 void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
205 {
206     QV8Engine::init(0);
207
208 #define CALL_ONMESSAGE_SCRIPT \
209     "(function(object, message) { "\
210         "var isfunction = false; "\
211         "try { "\
212             "isfunction = object.WorkerScript.onMessage instanceof Function; "\
213         "} catch (e) {}" \
214         "if (isfunction) "\
215             "object.WorkerScript.onMessage(message); "\
216     "})"
217
218 #define SEND_MESSAGE_CREATE_SCRIPT \
219     "(function(method, engine) { "\
220         "return (function(id) { "\
221             "return (function(message) { "\
222                 "if (arguments.length) method(engine, id, message); "\
223             "}); "\
224         "}); "\
225     "})"
226
227     v8::HandleScope handle_scope;
228     v8::Context::Scope scope(context());
229
230     {
231     v8::Local<v8::Script> onmessagescript = v8::Script::New(v8::String::New(CALL_ONMESSAGE_SCRIPT));
232     onmessage = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
233     }
234     {
235     v8::Local<v8::Script> createsendscript = v8::Script::New(v8::String::New(SEND_MESSAGE_CREATE_SCRIPT));
236     v8::Local<v8::Function> createsendconstructor = v8::Local<v8::Function>::Cast(createsendscript->Run());
237
238     v8::Handle<v8::Value> args[] = { 
239         V8FUNCTION(QDeclarativeWorkerScriptEnginePrivate::sendMessage, this)
240     };
241     v8::Local<v8::Value> createsendvalue = createsendconstructor->Call(global(), 1, args);
242     
243     createsend = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(createsendvalue));
244     }
245 }
246
247 // Requires handle and context scope
248 v8::Local<v8::Function> QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::sendFunction(int id)
249 {
250     v8::Handle<v8::Value> args[] = { v8::Integer::New(id) };
251     return v8::Local<v8::Function>::Cast(createsend->Call(global(), 1, args));
252 }
253
254 // Requires handle and context scope
255 void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::callOnMessage(v8::Handle<v8::Object> object, 
256                                                                         v8::Handle<v8::Value> arg)
257 {
258     v8::Handle<v8::Value> args[] = { object, arg };
259     onmessage->Call(global(), 2, args);
260 }
261
262 QNetworkAccessManager *QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager() 
263 {
264     if (!accessManager) {
265         if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
266             accessManager = p->qmlengine->networkAccessManagerFactory()->create(p);
267         } else {
268             accessManager = new QNetworkAccessManager(p);
269         }
270     }
271     return accessManager;
272 }
273
274 QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
275 : workerEngine(0), qmlengine(engine), m_nextId(0)
276 {
277 }
278
279 v8::Handle<v8::Value> QDeclarativeWorkerScriptEnginePrivate::sendMessage(const v8::Arguments &args)
280 {
281     WorkerEngine *engine = (WorkerEngine*)V8ENGINE();
282
283     int id = args[1]->Int32Value();
284
285     QByteArray data = QV8Worker::serialize(args[2], engine);
286
287     QMutexLocker(&engine->p->m_lock);
288     WorkerScript *script = engine->p->workers.value(id);
289     if (!script)
290         return v8::Undefined();
291
292     if (script->owner)
293         QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
294
295     return v8::Undefined();
296 }
297
298 // Requires handle scope and context scope
299 v8::Handle<v8::Object> QDeclarativeWorkerScriptEnginePrivate::getWorker(WorkerScript *script)
300 {
301     if (!script->initialized) {
302         script->initialized = true;
303
304         script->object = v8::Persistent<v8::Object>::New(workerEngine->contextWrapper()->urlScope(script->source));
305
306         workerEngine->contextWrapper()->setReadOnly(script->object, false);
307
308         v8::Local<v8::Object> api = v8::Object::New();
309         api->Set(v8::String::New("sendMessage"), workerEngine->sendFunction(script->id));
310
311         script->object->Set(v8::String::New("WorkerScript"), api);
312
313         workerEngine->contextWrapper()->setReadOnly(script->object, true);
314     }
315
316     return script->object;
317 }
318
319 bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
320 {
321     // XXX must handle remove request
322     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
323         WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
324         processMessage(workerEvent->workerId(), workerEvent->data());
325         return true;
326     } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
327         WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
328         processLoad(workerEvent->workerId(), workerEvent->url());
329         return true;
330     } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
331         emit stopThread();
332         return true;
333     } else {
334         return QObject::event(event);
335     }
336 }
337
338 void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
339 {
340     WorkerScript *script = workers.value(id);
341     if (!script)
342         return;
343
344     v8::HandleScope handle_scope;
345     v8::Context::Scope scope(workerEngine->context());
346
347     v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
348
349     v8::TryCatch tc;
350     workerEngine->callOnMessage(script->object, value);
351
352     if (tc.HasCaught()) {
353         QDeclarativeError error;
354         QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
355         reportScriptException(script, error);
356     }
357 }
358
359 void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
360 {
361     if (url.isRelative())
362         return;
363
364     QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
365
366     QFile f(fileName);
367     if (f.open(QIODevice::ReadOnly)) {
368         QByteArray data = f.readAll();
369         QString sourceCode = QString::fromUtf8(data);
370         QDeclarativeScriptParser::extractPragmas(sourceCode);
371
372         v8::HandleScope handle_scope;
373         v8::Context::Scope scope(workerEngine->context());
374
375         WorkerScript *script = workers.value(id);
376         if (!script)
377             return;
378         script->source = url;
379         v8::Handle<v8::Object> activation = getWorker(script);
380         if (activation.IsEmpty())
381             return;
382
383         // XXX ???
384         // workerEngine->baseUrl = url;
385
386         v8::TryCatch tc;
387         v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
388
389         if (!tc.HasCaught()) 
390             program->Run(activation);
391         
392         if (tc.HasCaught()) {
393             QDeclarativeError error;
394             QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
395             reportScriptException(script, error);
396         }
397     } else {
398         qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
399     }
400 }
401
402 void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script, 
403                                                                   const QDeclarativeError &error)
404 {
405     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine);
406
407     QMutexLocker(&p->m_lock);
408     if (script->owner)
409         QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
410 }
411
412 WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
413 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
414 {
415 }
416
417 WorkerDataEvent::~WorkerDataEvent()
418 {
419 }
420
421 int WorkerDataEvent::workerId() const
422 {
423     return m_id;
424 }
425
426 QByteArray WorkerDataEvent::data() const
427 {
428     return m_data;
429 }
430
431 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
432 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
433 {
434 }
435
436 int WorkerLoadEvent::workerId() const
437 {
438     return m_id;
439 }
440
441 QUrl WorkerLoadEvent::url() const
442 {
443     return m_url;
444 }
445
446 WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
447 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
448 {
449 }
450
451 int WorkerRemoveEvent::workerId() const
452 {
453     return m_id;
454 }
455
456 WorkerErrorEvent::WorkerErrorEvent(const QDeclarativeError &error)
457 : QEvent((QEvent::Type)WorkerError), m_error(error)
458 {
459 }
460
461 QDeclarativeError WorkerErrorEvent::error() const
462 {
463     return m_error;
464 }
465
466 QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent)
467 : QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent))
468 {
469     d->m_lock.lock();
470     connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
471     start(QThread::IdlePriority);
472     d->m_wait.wait(&d->m_lock);
473     d->moveToThread(this);
474     d->m_lock.unlock();
475 }
476
477 QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine()
478 {
479     d->m_lock.lock();
480     qDeleteAll(d->workers);
481     d->workers.clear();
482     QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent));
483     d->m_lock.unlock();
484
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     object.Dispose(); object.Clear();
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     v8::Isolate *isolate = v8::Isolate::New();
534     isolate->Enter();
535
536     d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::WorkerEngine(d);
537     d->workerEngine->init();
538
539     d->m_wait.wakeAll();
540
541     d->m_lock.unlock();
542
543     exec();
544
545     delete d->workerEngine; d->workerEngine = 0;
546
547     isolate->Exit();
548     isolate->Dispose();
549 }
550
551
552 /*!
553     \qmlclass WorkerScript QDeclarativeWorkerScript
554     \ingroup qml-utility-elements
555     \brief The WorkerScript element enables the use of threads in QML.
556
557     Use WorkerScript to run operations in a new thread.
558     This is useful for running operations in the background so
559     that the main GUI thread is not blocked.
560
561     Messages can be passed between the new thread and the parent thread
562     using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
563
564     An example:
565
566     \snippet doc/src/snippets/declarative/workerscript.qml 0
567
568     The above worker script specifies a JavaScript file, "script.js", that handles
569     the operations to be performed in the new thread. Here is \c script.js:
570
571     \quotefile doc/src/snippets/declarative/script.js
572
573     When the user clicks anywhere within the rectangle, \c sendMessage() is
574     called, triggering the \tt WorkerScript.onMessage() handler in
575     \tt script.js. This in turn sends a reply message that is then received
576     by the \tt onMessage() handler of \tt myWorker.
577
578
579     \section3 Restrictions
580
581     Since the \c WorkerScript.onMessage() function is run in a separate thread, the
582     JavaScript file is evaluated in a context separate from the main QML engine. This means
583     that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
584     in the above example cannot access the properties, methods or other attributes
585     of the QML item, nor can it access any context properties set on the QML object
586     through QDeclarativeContext.
587
588     Additionally, there are restrictions on the types of values that can be passed to and
589     from the worker script. See the sendMessage() documentation for details.
590
591     \sa {declarative/threading/workerscript}{WorkerScript example},
592         {declarative/threading/threadedlistmodel}{Threaded ListModel example}
593 */
594 QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent)
595 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
596 {
597 }
598
599 QDeclarativeWorkerScript::~QDeclarativeWorkerScript()
600 {
601     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
602 }
603
604 /*!
605     \qmlproperty url WorkerScript::source
606
607     This holds the url of the JavaScript file that implements the
608     \tt WorkerScript.onMessage() handler for threaded operations.
609 */
610 QUrl QDeclarativeWorkerScript::source() const
611 {
612     return m_source;
613 }
614
615 void QDeclarativeWorkerScript::setSource(const QUrl &source)
616 {
617     if (m_source == source)
618         return;
619
620     m_source = source;
621
622     if (engine())
623         m_engine->executeUrl(m_scriptId, m_source);
624
625     emit sourceChanged();
626 }
627
628 /*!
629     \qmlmethod WorkerScript::sendMessage(jsobject message)
630
631     Sends the given \a message to a worker script handler in another
632     thread. The other worker script handler can receive this message
633     through the onMessage() handler.
634
635     The \c message object may only contain values of the following
636     types:
637
638     \list
639     \o boolean, number, string
640     \o JavaScript objects and arrays
641     \o ListModel objects (any other type of QObject* is not allowed)
642     \endlist
643
644     All objects and arrays are copied to the \c message. With the exception
645     of ListModel objects, any modifications by the other thread to an object
646     passed in \c message will not be reflected in the original object.
647 */
648 void QDeclarativeWorkerScript::sendMessage(QDeclarativeV8Function *args)
649 {
650     if (!engine()) {
651         qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
652         return;
653     }
654
655     v8::Handle<v8::Value> argument = v8::Undefined();
656     if (args->Length() != 0) 
657         argument = (*args)[0];
658
659     m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
660 }
661
662 void QDeclarativeWorkerScript::classBegin()
663 {
664     m_componentComplete = false;
665 }
666
667 QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine()
668 {
669     if (m_engine) return m_engine;
670     if (m_componentComplete) {
671         QDeclarativeEngine *engine = qmlEngine(this);
672         if (!engine) {
673             qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set");
674             return 0;
675         }
676
677         m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine();
678         m_scriptId = m_engine->registerWorkerScript(this);
679
680         if (m_source.isValid())
681             m_engine->executeUrl(m_scriptId, m_source);
682
683         return m_engine;
684     }
685     return 0;
686 }
687
688 void QDeclarativeWorkerScript::componentComplete()
689 {
690     m_componentComplete = true;
691     engine(); // Get it started now.
692 }
693
694 /*!
695     \qmlsignal WorkerScript::onMessage(jsobject msg)
696
697     This handler is called when a message \a msg is received from a worker
698     script in another thread through a call to sendMessage().
699 */
700
701 bool QDeclarativeWorkerScript::event(QEvent *event)
702 {
703     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
704         QDeclarativeEngine *engine = qmlEngine(this);
705         if (engine) {
706             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
707             QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine;
708             v8::HandleScope handle_scope;
709             v8::Context::Scope scope(v8engine->context());
710             v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
711             emit message(QDeclarativeV8Handle::fromHandle(value));
712         }
713         return true;
714     } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
715         WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
716         QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error());
717         return true;
718     } else {
719         return QObject::event(event);
720     }
721 }
722
723 QT_END_NAMESPACE
724
725 #include <qdeclarativeworkerscript.moc>
726