|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtDeclarative module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "private/qdeclarativeworkerscript_p.h" |
|
43 #include "private/qdeclarativelistmodel_p.h" |
|
44 #include "private/qdeclarativelistmodelworkeragent_p.h" |
|
45 #include "private/qdeclarativeengine_p.h" |
|
46 |
|
47 #include <QtCore/qcoreevent.h> |
|
48 #include <QtCore/qcoreapplication.h> |
|
49 #include <QtCore/qdebug.h> |
|
50 #include <QtScript/qscriptengine.h> |
|
51 #include <QtCore/qmutex.h> |
|
52 #include <QtCore/qwaitcondition.h> |
|
53 #include <QtScript/qscriptvalueiterator.h> |
|
54 #include <QtCore/qfile.h> |
|
55 #include <QtNetwork/qnetworkaccessmanager.h> |
|
56 #include <QtDeclarative/qdeclarativeinfo.h> |
|
57 #include "qdeclarativenetworkaccessmanagerfactory.h" |
|
58 |
|
59 |
|
60 QT_BEGIN_NAMESPACE |
|
61 |
|
62 class WorkerDataEvent : public QEvent |
|
63 { |
|
64 public: |
|
65 enum Type { WorkerData = QEvent::User }; |
|
66 |
|
67 WorkerDataEvent(int workerId, const QVariant &data); |
|
68 virtual ~WorkerDataEvent(); |
|
69 |
|
70 int workerId() const; |
|
71 QVariant data() const; |
|
72 |
|
73 private: |
|
74 int m_id; |
|
75 QVariant m_data; |
|
76 }; |
|
77 |
|
78 class WorkerLoadEvent : public QEvent |
|
79 { |
|
80 public: |
|
81 enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 }; |
|
82 |
|
83 WorkerLoadEvent(int workerId, const QUrl &url); |
|
84 |
|
85 int workerId() const; |
|
86 QUrl url() const; |
|
87 |
|
88 private: |
|
89 int m_id; |
|
90 QUrl m_url; |
|
91 }; |
|
92 |
|
93 class WorkerRemoveEvent : public QEvent |
|
94 { |
|
95 public: |
|
96 enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 }; |
|
97 |
|
98 WorkerRemoveEvent(int workerId); |
|
99 |
|
100 int workerId() const; |
|
101 |
|
102 private: |
|
103 int m_id; |
|
104 }; |
|
105 |
|
106 class QDeclarativeWorkerScriptEnginePrivate : public QObject |
|
107 { |
|
108 Q_OBJECT |
|
109 public: |
|
110 enum WorkerEventTypes { |
|
111 WorkerDestroyEvent = QEvent::User + 100 |
|
112 }; |
|
113 |
|
114 QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng); |
|
115 |
|
116 struct ScriptEngine : public QDeclarativeScriptEngine |
|
117 { |
|
118 ScriptEngine(QDeclarativeWorkerScriptEnginePrivate *parent) : QDeclarativeScriptEngine(0), p(parent), accessManager(0) {} |
|
119 ~ScriptEngine() { delete accessManager; } |
|
120 QDeclarativeWorkerScriptEnginePrivate *p; |
|
121 QNetworkAccessManager *accessManager; |
|
122 |
|
123 virtual QNetworkAccessManager *networkAccessManager() { |
|
124 if (!accessManager) { |
|
125 if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) { |
|
126 accessManager = p->qmlengine->networkAccessManagerFactory()->create(this); |
|
127 } else { |
|
128 accessManager = new QNetworkAccessManager(this); |
|
129 } |
|
130 } |
|
131 return accessManager; |
|
132 } |
|
133 }; |
|
134 ScriptEngine *workerEngine; |
|
135 static QDeclarativeWorkerScriptEnginePrivate *get(QScriptEngine *e) { |
|
136 return static_cast<ScriptEngine *>(e)->p; |
|
137 } |
|
138 |
|
139 QDeclarativeEngine *qmlengine; |
|
140 |
|
141 QMutex m_lock; |
|
142 QWaitCondition m_wait; |
|
143 |
|
144 struct WorkerScript { |
|
145 WorkerScript(); |
|
146 |
|
147 int id; |
|
148 bool initialized; |
|
149 QDeclarativeWorkerScript *owner; |
|
150 QScriptValue object; |
|
151 |
|
152 QScriptValue callback; |
|
153 }; |
|
154 |
|
155 QHash<int, WorkerScript *> workers; |
|
156 QScriptValue getWorker(int); |
|
157 |
|
158 int m_nextId; |
|
159 |
|
160 static QVariant scriptValueToVariant(const QScriptValue &); |
|
161 static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *); |
|
162 |
|
163 static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine); |
|
164 static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine); |
|
165 |
|
166 signals: |
|
167 void stopThread(); |
|
168 |
|
169 protected: |
|
170 virtual bool event(QEvent *); |
|
171 |
|
172 private: |
|
173 void processMessage(int, const QVariant &); |
|
174 void processLoad(int, const QUrl &); |
|
175 }; |
|
176 |
|
177 QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine) |
|
178 : workerEngine(0), qmlengine(engine), m_nextId(0) |
|
179 { |
|
180 } |
|
181 |
|
182 QScriptValue QDeclarativeWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine) |
|
183 { |
|
184 QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine); |
|
185 |
|
186 int id = ctxt->thisObject().data().toVariant().toInt(); |
|
187 |
|
188 WorkerScript *script = p->workers.value(id); |
|
189 if (!script) |
|
190 return engine->undefinedValue(); |
|
191 |
|
192 if (ctxt->argumentCount() >= 1) |
|
193 script->callback = ctxt->argument(0); |
|
194 |
|
195 return script->callback; |
|
196 } |
|
197 |
|
198 QScriptValue QDeclarativeWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine) |
|
199 { |
|
200 if (!ctxt->argumentCount()) |
|
201 return engine->undefinedValue(); |
|
202 |
|
203 QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine); |
|
204 |
|
205 int id = ctxt->thisObject().data().toVariant().toInt(); |
|
206 |
|
207 WorkerScript *script = p->workers.value(id); |
|
208 if (!script) |
|
209 return engine->undefinedValue(); |
|
210 |
|
211 QMutexLocker(&p->m_lock); |
|
212 |
|
213 if (script->owner) |
|
214 QCoreApplication::postEvent(script->owner, |
|
215 new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0)))); |
|
216 |
|
217 return engine->undefinedValue(); |
|
218 } |
|
219 |
|
220 QScriptValue QDeclarativeWorkerScriptEnginePrivate::getWorker(int id) |
|
221 { |
|
222 QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id); |
|
223 |
|
224 if (iter == workers.end()) |
|
225 return workerEngine->nullValue(); |
|
226 |
|
227 WorkerScript *script = *iter; |
|
228 if (!script->initialized) { |
|
229 |
|
230 script->initialized = true; |
|
231 script->object = workerEngine->newObject(); |
|
232 |
|
233 QScriptValue api = workerEngine->newObject(); |
|
234 api.setData(script->id); |
|
235 |
|
236 api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage), |
|
237 QScriptValue::PropertyGetter | QScriptValue::PropertySetter); |
|
238 api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage)); |
|
239 |
|
240 script->object.setProperty(QLatin1String("WorkerScript"), api); |
|
241 } |
|
242 |
|
243 return script->object; |
|
244 } |
|
245 |
|
246 bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event) |
|
247 { |
|
248 if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { |
|
249 WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); |
|
250 processMessage(workerEvent->workerId(), workerEvent->data()); |
|
251 return true; |
|
252 } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) { |
|
253 WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event); |
|
254 processLoad(workerEvent->workerId(), workerEvent->url()); |
|
255 return true; |
|
256 } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) { |
|
257 emit stopThread(); |
|
258 return true; |
|
259 } else { |
|
260 return QObject::event(event); |
|
261 } |
|
262 } |
|
263 |
|
264 void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data) |
|
265 { |
|
266 WorkerScript *script = workers.value(id); |
|
267 if (!script) |
|
268 return; |
|
269 |
|
270 if (script->callback.isFunction()) { |
|
271 QScriptValue args = workerEngine->newArray(1); |
|
272 args.setProperty(0, variantToScriptValue(data, workerEngine)); |
|
273 |
|
274 script->callback.call(script->object, args); |
|
275 } |
|
276 } |
|
277 |
|
278 void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) |
|
279 { |
|
280 if (url.isRelative()) |
|
281 return; |
|
282 |
|
283 QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url); |
|
284 |
|
285 QFile f(fileName); |
|
286 if (f.open(QIODevice::ReadOnly)) { |
|
287 QByteArray data = f.readAll(); |
|
288 QString script = QString::fromUtf8(data); |
|
289 |
|
290 QScriptValue activation = getWorker(id); |
|
291 |
|
292 QScriptContext *ctxt = QScriptDeclarativeClass::pushCleanContext(workerEngine); |
|
293 QScriptValue urlContext = workerEngine->newObject(); |
|
294 urlContext.setData(QScriptValue(workerEngine, fileName)); |
|
295 ctxt->pushScope(urlContext); |
|
296 ctxt->pushScope(activation); |
|
297 ctxt->setActivationObject(activation); |
|
298 |
|
299 workerEngine->baseUrl = url; |
|
300 workerEngine->evaluate(script); |
|
301 |
|
302 workerEngine->popContext(); |
|
303 } else { |
|
304 qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString(); |
|
305 } |
|
306 } |
|
307 |
|
308 QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value) |
|
309 { |
|
310 if (value.isBool()) { |
|
311 return QVariant(value.toBool()); |
|
312 } else if (value.isString()) { |
|
313 return QVariant(value.toString()); |
|
314 } else if (value.isNumber()) { |
|
315 return QVariant((qreal)value.toNumber()); |
|
316 } else if (value.isArray()) { |
|
317 QVariantList list; |
|
318 |
|
319 quint32 length = (quint32)value.property(QLatin1String("length")).toNumber(); |
|
320 |
|
321 for (quint32 ii = 0; ii < length; ++ii) { |
|
322 QVariant v = scriptValueToVariant(value.property(ii)); |
|
323 list << v; |
|
324 } |
|
325 |
|
326 return QVariant(list); |
|
327 } else if (value.isQObject()) { |
|
328 QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject()); |
|
329 if (lm) { |
|
330 QDeclarativeListModelWorkerAgent *agent = lm->agent(); |
|
331 if (agent) { |
|
332 QDeclarativeListModelWorkerAgent::VariantRef v(agent); |
|
333 return qVariantFromValue(v); |
|
334 } else { |
|
335 return QVariant(); |
|
336 } |
|
337 } else { |
|
338 // No other QObject's are allowed to be sent |
|
339 return QVariant(); |
|
340 } |
|
341 } else if (value.isObject()) { |
|
342 QVariantHash hash; |
|
343 |
|
344 QScriptValueIterator iter(value); |
|
345 |
|
346 while (iter.hasNext()) { |
|
347 iter.next(); |
|
348 hash.insert(iter.name(), scriptValueToVariant(iter.value())); |
|
349 } |
|
350 |
|
351 return QVariant(hash); |
|
352 } |
|
353 |
|
354 return QVariant(); |
|
355 |
|
356 } |
|
357 |
|
358 QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine) |
|
359 { |
|
360 if (value.userType() == QVariant::Bool) { |
|
361 return QScriptValue(value.toBool()); |
|
362 } else if (value.userType() == QVariant::String) { |
|
363 return QScriptValue(value.toString()); |
|
364 } else if (value.userType() == QMetaType::QReal) { |
|
365 return QScriptValue(value.toReal()); |
|
366 } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) { |
|
367 QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value); |
|
368 if (vr.a->scriptEngine() == 0) |
|
369 vr.a->setScriptEngine(engine); |
|
370 else if (vr.a->scriptEngine() != engine) |
|
371 return engine->nullValue(); |
|
372 QScriptValue o = engine->newQObject(vr.a); |
|
373 o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc |
|
374 return o; |
|
375 } else if (value.userType() == QMetaType::QVariantList) { |
|
376 QVariantList list = qvariant_cast<QVariantList>(value); |
|
377 QScriptValue rv = engine->newArray(list.count()); |
|
378 |
|
379 for (quint32 ii = 0; ii < quint32(list.count()); ++ii) |
|
380 rv.setProperty(ii, variantToScriptValue(list.at(ii), engine)); |
|
381 |
|
382 return rv; |
|
383 } else if (value.userType() == QMetaType::QVariantHash) { |
|
384 |
|
385 QVariantHash hash = qvariant_cast<QVariantHash>(value); |
|
386 |
|
387 QScriptValue rv = engine->newObject(); |
|
388 |
|
389 for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter) |
|
390 rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine)); |
|
391 |
|
392 return rv; |
|
393 } else { |
|
394 return engine->nullValue(); |
|
395 } |
|
396 } |
|
397 |
|
398 WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data) |
|
399 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data) |
|
400 { |
|
401 } |
|
402 |
|
403 WorkerDataEvent::~WorkerDataEvent() |
|
404 { |
|
405 } |
|
406 |
|
407 int WorkerDataEvent::workerId() const |
|
408 { |
|
409 return m_id; |
|
410 } |
|
411 |
|
412 QVariant WorkerDataEvent::data() const |
|
413 { |
|
414 return m_data; |
|
415 } |
|
416 |
|
417 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url) |
|
418 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url) |
|
419 { |
|
420 } |
|
421 |
|
422 int WorkerLoadEvent::workerId() const |
|
423 { |
|
424 return m_id; |
|
425 } |
|
426 |
|
427 QUrl WorkerLoadEvent::url() const |
|
428 { |
|
429 return m_url; |
|
430 } |
|
431 |
|
432 WorkerRemoveEvent::WorkerRemoveEvent(int workerId) |
|
433 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId) |
|
434 { |
|
435 } |
|
436 |
|
437 int WorkerRemoveEvent::workerId() const |
|
438 { |
|
439 return m_id; |
|
440 } |
|
441 |
|
442 QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent) |
|
443 : QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent)) |
|
444 { |
|
445 d->m_lock.lock(); |
|
446 connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection); |
|
447 start(QThread::LowPriority); |
|
448 d->m_wait.wait(&d->m_lock); |
|
449 d->moveToThread(this); |
|
450 d->m_lock.unlock(); |
|
451 } |
|
452 |
|
453 QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine() |
|
454 { |
|
455 d->m_lock.lock(); |
|
456 qDeleteAll(d->workers); |
|
457 d->workers.clear(); |
|
458 QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent)); |
|
459 d->m_lock.unlock(); |
|
460 |
|
461 wait(); |
|
462 d->deleteLater(); |
|
463 } |
|
464 |
|
465 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript() |
|
466 : id(-1), initialized(false), owner(0) |
|
467 { |
|
468 } |
|
469 |
|
470 int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner) |
|
471 { |
|
472 QDeclarativeWorkerScriptEnginePrivate::WorkerScript *script = new QDeclarativeWorkerScriptEnginePrivate::WorkerScript; |
|
473 script->id = d->m_nextId++; |
|
474 script->owner = owner; |
|
475 |
|
476 d->m_lock.lock(); |
|
477 d->workers.insert(script->id, script); |
|
478 d->m_lock.unlock(); |
|
479 |
|
480 return script->id; |
|
481 } |
|
482 |
|
483 void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id) |
|
484 { |
|
485 QCoreApplication::postEvent(d, new WorkerRemoveEvent(id)); |
|
486 } |
|
487 |
|
488 void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url) |
|
489 { |
|
490 QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url)); |
|
491 } |
|
492 |
|
493 void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QVariant &data) |
|
494 { |
|
495 QCoreApplication::postEvent(d, new WorkerDataEvent(id, data)); |
|
496 } |
|
497 |
|
498 void QDeclarativeWorkerScriptEngine::run() |
|
499 { |
|
500 d->m_lock.lock(); |
|
501 |
|
502 d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::ScriptEngine(d); |
|
503 |
|
504 d->m_wait.wakeAll(); |
|
505 |
|
506 d->m_lock.unlock(); |
|
507 |
|
508 exec(); |
|
509 |
|
510 delete d->workerEngine; d->workerEngine = 0; |
|
511 } |
|
512 |
|
513 |
|
514 /*! |
|
515 \qmlclass WorkerScript QDeclarativeWorkerScript |
|
516 \brief The WorkerScript element enables the use of threads in QML. |
|
517 |
|
518 Use WorkerScript to run operations in a new thread. |
|
519 This is useful for running operations in the background so |
|
520 that the main GUI thread is not blocked. |
|
521 |
|
522 Messages can be passed between the new thread and the parent thread |
|
523 using sendMessage() and the onMessage() handler. |
|
524 |
|
525 Here is an example: |
|
526 |
|
527 \snippet doc/src/snippets/declarative/workerscript.qml 0 |
|
528 |
|
529 The above worker script specifies a javascript file, "script.js", that handles |
|
530 the operations to be performed in the new thread. Here is \c script.js: |
|
531 |
|
532 \qml |
|
533 WorkerScript.onMessage = function(message) { |
|
534 // ... long-running operations and calculations are done here |
|
535 WorkerScript.sendMessage({ 'reply': 'Mouse is at ' + message.x + ',' + message.y }) |
|
536 } |
|
537 \endqml |
|
538 |
|
539 When the user clicks anywhere within the rectangle, \c sendMessage() is |
|
540 called, triggering the \tt WorkerScript.onMessage() handler in |
|
541 \tt script.js. This in turn sends a reply message that is then received |
|
542 by the \tt onMessage() handler of \tt myWorker. |
|
543 */ |
|
544 QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent) |
|
545 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true) |
|
546 { |
|
547 } |
|
548 |
|
549 QDeclarativeWorkerScript::~QDeclarativeWorkerScript() |
|
550 { |
|
551 if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId); |
|
552 } |
|
553 |
|
554 /*! |
|
555 \qmlproperty url WorkerScript::source |
|
556 |
|
557 This holds the url of the javascript file that implements the |
|
558 \tt WorkerScript.onMessage() handler for threaded operations. |
|
559 */ |
|
560 QUrl QDeclarativeWorkerScript::source() const |
|
561 { |
|
562 return m_source; |
|
563 } |
|
564 |
|
565 void QDeclarativeWorkerScript::setSource(const QUrl &source) |
|
566 { |
|
567 if (m_source == source) |
|
568 return; |
|
569 |
|
570 m_source = source; |
|
571 |
|
572 if (engine()) |
|
573 m_engine->executeUrl(m_scriptId, m_source); |
|
574 |
|
575 emit sourceChanged(); |
|
576 } |
|
577 |
|
578 /* |
|
579 \qmlmethod WorkerScript::sendMessage(jsobject message) |
|
580 |
|
581 Sends the given \a message to a worker script handler in another |
|
582 thread. The other worker script handler can receive this message |
|
583 through the onMessage() handler. |
|
584 */ |
|
585 void QDeclarativeWorkerScript::sendMessage(const QScriptValue &message) |
|
586 { |
|
587 if (!engine()) { |
|
588 qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment"); |
|
589 return; |
|
590 } |
|
591 |
|
592 m_engine->sendMessage(m_scriptId, QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(message)); |
|
593 } |
|
594 |
|
595 void QDeclarativeWorkerScript::classBegin() |
|
596 { |
|
597 m_componentComplete = false; |
|
598 } |
|
599 |
|
600 QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine() |
|
601 { |
|
602 if (m_engine) return m_engine; |
|
603 if (m_componentComplete) { |
|
604 QDeclarativeEngine *engine = qmlEngine(this); |
|
605 if (!engine) { |
|
606 qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set"); |
|
607 return 0; |
|
608 } |
|
609 |
|
610 m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine(); |
|
611 m_scriptId = m_engine->registerWorkerScript(this); |
|
612 |
|
613 if (m_source.isValid()) |
|
614 m_engine->executeUrl(m_scriptId, m_source); |
|
615 |
|
616 return m_engine; |
|
617 } |
|
618 return 0; |
|
619 } |
|
620 |
|
621 void QDeclarativeWorkerScript::componentComplete() |
|
622 { |
|
623 m_componentComplete = true; |
|
624 engine(); // Get it started now. |
|
625 } |
|
626 |
|
627 /*! |
|
628 \qmlsignal WorkerScript::onMessage(jsobject msg) |
|
629 |
|
630 This handler is called when a message \a msg is received from a worker |
|
631 script in another thread through a call to sendMessage(). |
|
632 */ |
|
633 |
|
634 bool QDeclarativeWorkerScript::event(QEvent *event) |
|
635 { |
|
636 if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { |
|
637 QDeclarativeEngine *engine = qmlEngine(this); |
|
638 if (engine) { |
|
639 QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); |
|
640 WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); |
|
641 QScriptValue value = |
|
642 QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine); |
|
643 emit message(value); |
|
644 } |
|
645 return true; |
|
646 } else { |
|
647 return QObject::event(event); |
|
648 } |
|
649 } |
|
650 |
|
651 QT_END_NAMESPACE |
|
652 |
|
653 #include <qdeclarativeworkerscript.moc> |
|
654 |