Skip to content

Latest commit

 

History

History
702 lines (585 loc) · 21.7 KB

qqmlincubator.cpp

File metadata and controls

702 lines (585 loc) · 21.7 KB
 
Sep 29, 2011
Sep 29, 2011
1
2
/****************************************************************************
**
Jan 5, 2012
Jan 5, 2012
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
Jan 23, 2012
Jan 23, 2012
4
** Contact: http://www.qt-project.org/
Sep 29, 2011
Sep 29, 2011
5
**
Feb 24, 2012
Feb 24, 2012
6
** This file is part of the QtQml module of the Qt Toolkit.
Sep 29, 2011
Sep 29, 2011
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
Jan 30, 2012
Jan 30, 2012
37
**
Sep 29, 2011
Sep 29, 2011
38
39
40
41
** $QT_END_LICENSE$
**
****************************************************************************/
Feb 24, 2012
Feb 24, 2012
42
43
44
#include "qqmlincubator.h"
#include "qqmlcomponent.h"
#include "qqmlincubator_p.h"
Sep 29, 2011
Sep 29, 2011
45
Feb 24, 2012
Feb 24, 2012
46
47
#include "qqmlcompiler_p.h"
#include "qqmlexpression_p.h"
Sep 29, 2011
Sep 29, 2011
48
49
50
51
// XXX TODO
// - check that the Component.onCompleted behavior is the same as 4.8 in the synchronous and
// async if nested cases
Feb 24, 2012
Feb 24, 2012
52
void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
Sep 29, 2011
Sep 29, 2011
53
{
Feb 24, 2012
Feb 24, 2012
54
QQmlIncubatorPrivate *p = i.d;
Sep 29, 2011
Sep 29, 2011
55
Feb 24, 2012
Feb 24, 2012
56
QQmlIncubator::IncubationMode mode = i.incubationMode();
Sep 29, 2011
Sep 29, 2011
57
Oct 4, 2011
Oct 4, 2011
58
if (!incubationController)
Feb 24, 2012
Feb 24, 2012
59
mode = QQmlIncubator::Synchronous;
Oct 4, 2011
Oct 4, 2011
60
Feb 24, 2012
Feb 24, 2012
61
62
if (mode == QQmlIncubator::AsynchronousIfNested) {
mode = QQmlIncubator::Synchronous;
Sep 29, 2011
Sep 29, 2011
63
64
// Need to find the first constructing context and see if it is asynchronous
Feb 24, 2012
Feb 24, 2012
65
66
QQmlIncubatorPrivate *parentIncubator = 0;
QQmlContextData *cctxt = forContext;
Sep 29, 2011
Sep 29, 2011
67
while (cctxt) {
Nov 1, 2011
Nov 1, 2011
68
if (cctxt->activeVMEData) {
Feb 24, 2012
Feb 24, 2012
69
parentIncubator = (QQmlIncubatorPrivate *)cctxt->activeVMEData;
Sep 29, 2011
Sep 29, 2011
70
71
72
73
74
break;
}
cctxt = cctxt->parent;
}
Oct 20, 2011
Oct 20, 2011
75
if (parentIncubator && parentIncubator->isAsynchronous) {
Feb 24, 2012
Feb 24, 2012
76
mode = QQmlIncubator::Asynchronous;
Sep 29, 2011
Sep 29, 2011
77
78
79
80
81
p->waitingOnMe = parentIncubator;
parentIncubator->waitingFor.insert(p);
}
}
Feb 24, 2012
Feb 24, 2012
82
p->isAsynchronous = (mode != QQmlIncubator::Synchronous);
Oct 20, 2011
Oct 20, 2011
83
Oct 4, 2011
Oct 4, 2011
84
85
inProgressCreations++;
Feb 24, 2012
Feb 24, 2012
86
87
if (mode == QQmlIncubator::Synchronous) {
typedef QQmlIncubatorPrivate IP;
Oct 20, 2011
Oct 20, 2011
88
89
QRecursionWatcher<IP, &IP::recursion> watcher(p);
Feb 24, 2012
Feb 24, 2012
90
p->changeStatus(QQmlIncubator::Loading);
Oct 20, 2011
Oct 20, 2011
91
92
if (!watcher.hasRecursed()) {
Feb 24, 2012
Feb 24, 2012
93
QQmlVME::Interrupt i;
Oct 20, 2011
Oct 20, 2011
94
95
p->incubate(i);
}
Sep 29, 2011
Sep 29, 2011
96
97
98
99
} else {
incubatorList.insert(p);
incubatorCount++;
Nov 17, 2011
Nov 17, 2011
100
p->vmeGuard.guard(&p->vme);
Feb 24, 2012
Feb 24, 2012
101
p->changeStatus(QQmlIncubator::Loading);
Oct 20, 2011
Oct 20, 2011
102
Sep 29, 2011
Sep 29, 2011
103
104
105
106
107
if (incubationController)
incubationController->incubatingObjectCountChanged(incubatorCount);
}
}
Sep 29, 2011
Sep 29, 2011
108
109
110
111
112
113
/*!
Sets the engine's incubation \a controller. The engine can only have one active controller
and it does not take ownership of it.
\sa incubationController()
*/
Feb 24, 2012
Feb 24, 2012
114
void QQmlEngine::setIncubationController(QQmlIncubationController *controller)
Sep 29, 2011
Sep 29, 2011
115
{
Feb 24, 2012
Feb 24, 2012
116
Q_D(QQmlEngine);
Nov 1, 2011
Nov 1, 2011
117
118
if (d->incubationController)
d->incubationController->d = 0;
Sep 29, 2011
Sep 29, 2011
119
120
d->incubationController = controller;
if (controller) controller->d = d;
Sep 29, 2011
Sep 29, 2011
121
122
}
Sep 29, 2011
Sep 29, 2011
123
124
125
126
127
/*!
Returns the currently set incubation controller, or 0 if no controller has been set.
\sa setIncubationController()
*/
Feb 24, 2012
Feb 24, 2012
128
QQmlIncubationController *QQmlEngine::incubationController() const
Sep 29, 2011
Sep 29, 2011
129
{
Feb 24, 2012
Feb 24, 2012
130
Q_D(const QQmlEngine);
Sep 29, 2011
Sep 29, 2011
131
132
133
return d->incubationController;
}
Feb 24, 2012
Feb 24, 2012
134
135
136
QQmlIncubatorPrivate::QQmlIncubatorPrivate(QQmlIncubator *q,
QQmlIncubator::IncubationMode m)
: q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute),
Oct 20, 2011
Oct 20, 2011
137
result(0), component(0), vme(this), waitingOnMe(0)
Sep 29, 2011
Sep 29, 2011
138
139
140
{
}
Feb 24, 2012
Feb 24, 2012
141
QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
Sep 29, 2011
Sep 29, 2011
142
143
144
{
}
Feb 24, 2012
Feb 24, 2012
145
void QQmlIncubatorPrivate::clear()
Sep 29, 2011
Sep 29, 2011
146
147
148
149
{
if (next.isInList()) {
next.remove();
Q_ASSERT(component);
Feb 24, 2012
Feb 24, 2012
150
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(component->engine);
Sep 29, 2011
Sep 29, 2011
151
component->release();
Sep 30, 2011
Sep 30, 2011
152
component = 0;
Sep 29, 2011
Sep 29, 2011
153
enginePriv->incubatorCount--;
Feb 24, 2012
Feb 24, 2012
154
QQmlIncubationController *controller = enginePriv->incubationController;
Sep 29, 2011
Sep 29, 2011
155
156
if (controller)
controller->incubatingObjectCountChanged(enginePriv->incubatorCount);
Oct 4, 2011
Oct 4, 2011
157
158
159
} else if (component) {
component->release();
component = 0;
Sep 29, 2011
Sep 29, 2011
160
}
Nov 1, 2011
Nov 1, 2011
161
162
163
164
if (!rootContext.isNull()) {
rootContext->activeVMEData = 0;
rootContext = 0;
}
Sep 29, 2011
Sep 29, 2011
165
166
167
168
169
170
171
172
if (nextWaitingFor.isInList()) {
Q_ASSERT(waitingOnMe);
nextWaitingFor.remove();
waitingOnMe = 0;
}
}
Sep 29, 2011
Sep 29, 2011
173
/*!
Feb 24, 2012
Feb 24, 2012
174
175
\class QQmlIncubationController
\brief QQmlIncubationController instances drive the progress of QQmlIncubators
Sep 29, 2011
Sep 29, 2011
176
177
In order to behave asynchronously and not introduce stutters or freezes in an application,
Feb 24, 2012
Feb 24, 2012
178
179
the process of creating objects a QQmlIncubators must be driven only during the
application's idle time. QQmlIncubationController allows the application to control
Sep 29, 2011
Sep 29, 2011
180
181
exactly when, how often and for how long this processing occurs.
Feb 24, 2012
Feb 24, 2012
182
183
184
185
A QQmlIncubationController derived instance should be created and set on a
QQmlEngine by calling the QQmlEngine::setIncubationController() method.
Processing is then controlled by calling the QQmlIncubationController::incubateFor()
or QQmlIncubationController::incubateWhile() methods as dictated by the application's
Sep 29, 2011
Sep 29, 2011
186
187
188
189
190
191
192
requirements.
For example, this is an example of a incubation controller that will incubate for a maximum
of 5 milliseconds out of every 16 milliseconds.
\code
class PeriodicIncubationController : public QObject,
Feb 24, 2012
Feb 24, 2012
193
public QQmlIncubationController
Sep 29, 2011
Sep 29, 2011
194
195
196
197
198
199
200
201
202
203
204
205
{
public:
PeriodicIncubationController() {
startTimer(16);
}
protected:
virtual void timerEvent(QTimerEvent *) {
incubateFor(5);
}
};
\endcode
Sep 29, 2011
Sep 29, 2011
206
Sep 29, 2011
Sep 29, 2011
207
208
209
Although the previous example would work, it is not optimal. Real world incubation
controllers should try and maximize the amount of idle time they consume - rather
than a static amount like 5 milliseconds - while not disturbing the application.
Sep 29, 2011
Sep 29, 2011
210
211
*/
Sep 29, 2011
Sep 29, 2011
212
213
214
/*!
Create a new incubation controller.
*/
Feb 24, 2012
Feb 24, 2012
215
QQmlIncubationController::QQmlIncubationController()
Sep 29, 2011
Sep 29, 2011
216
217
218
219
: d(0)
{
}
Sep 29, 2011
Sep 29, 2011
220
/*! \internal */
Feb 24, 2012
Feb 24, 2012
221
QQmlIncubationController::~QQmlIncubationController()
Sep 29, 2011
Sep 29, 2011
222
{
Feb 24, 2012
Feb 24, 2012
223
if (d) QQmlEnginePrivate::get(d)->setIncubationController(0);
Sep 29, 2011
Sep 29, 2011
224
225
226
d = 0;
}
Sep 29, 2011
Sep 29, 2011
227
/*!
Feb 24, 2012
Feb 24, 2012
228
Return the QQmlEngine this incubation controller is set on, or 0 if it
Sep 29, 2011
Sep 29, 2011
229
230
has not been set on any engine.
*/
Feb 24, 2012
Feb 24, 2012
231
QQmlEngine *QQmlIncubationController::engine() const
Sep 29, 2011
Sep 29, 2011
232
{
Feb 24, 2012
Feb 24, 2012
233
return QQmlEnginePrivate::get(d);
Sep 29, 2011
Sep 29, 2011
234
235
}
Sep 29, 2011
Sep 29, 2011
236
237
238
/*!
Return the number of objects currently incubating.
*/
Feb 24, 2012
Feb 24, 2012
239
int QQmlIncubationController::incubatingObjectCount() const
Sep 29, 2011
Sep 29, 2011
240
241
242
243
244
245
246
{
if (d)
return d->incubatorCount;
else
return 0;
}
Sep 29, 2011
Sep 29, 2011
247
248
249
250
251
252
/*!
Called when the number of incubating objects changes. \a incubatingObjectCount is the
new number of incubating objects.
The default implementation does nothing.
*/
Feb 24, 2012
Feb 24, 2012
253
void QQmlIncubationController::incubatingObjectCountChanged(int incubatingObjectCount)
Sep 29, 2011
Sep 29, 2011
254
{
Sep 29, 2011
Sep 29, 2011
255
Q_UNUSED(incubatingObjectCount);
Sep 29, 2011
Sep 29, 2011
256
257
}
Feb 24, 2012
Feb 24, 2012
258
void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
Sep 29, 2011
Sep 29, 2011
259
{
Nov 1, 2011
Nov 1, 2011
260
261
if (!component)
return;
Feb 24, 2012
Feb 24, 2012
262
typedef QQmlIncubatorPrivate IP;
Oct 6, 2011
Oct 6, 2011
263
264
QRecursionWatcher<IP, &IP::recursion> watcher(this);
Feb 24, 2012
Feb 24, 2012
265
266
QQmlEngine *engine = component->engine;
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
Sep 29, 2011
Sep 29, 2011
267
Oct 3, 2011
Oct 3, 2011
268
269
270
271
bool guardOk = vmeGuard.isOK();
vmeGuard.clear();
if (!guardOk) {
Feb 24, 2012
Feb 24, 2012
272
QQmlError error;
Oct 3, 2011
Oct 3, 2011
273
error.setUrl(component->url);
Feb 24, 2012
Feb 24, 2012
274
error.setDescription(QQmlComponent::tr("Object destroyed during incubation"));
Oct 3, 2011
Oct 3, 2011
275
errors << error;
Feb 24, 2012
Feb 24, 2012
276
progress = QQmlIncubatorPrivate::Completed;
Oct 3, 2011
Oct 3, 2011
277
278
279
280
goto finishIncubate;
}
Feb 24, 2012
Feb 24, 2012
281
if (progress == QQmlIncubatorPrivate::Execute) {
Sep 29, 2011
Sep 29, 2011
282
enginePriv->referenceScarceResources();
Oct 6, 2011
Oct 6, 2011
283
QObject *tresult = vme.execute(&errors, i);
Sep 29, 2011
Sep 29, 2011
284
285
enginePriv->dereferenceScarceResources();
Oct 6, 2011
Oct 6, 2011
286
287
288
289
if (watcher.hasRecursed())
return;
result = tresult;
Sep 29, 2011
Sep 29, 2011
290
if (errors.isEmpty() && result == 0)
Oct 3, 2011
Oct 3, 2011
291
goto finishIncubate;
Sep 29, 2011
Sep 29, 2011
292
293
if (result) {
Feb 24, 2012
Feb 24, 2012
294
QQmlData *ddata = QQmlData::get(result);
Sep 29, 2011
Sep 29, 2011
295
Q_ASSERT(ddata);
Mar 23, 2012
Mar 23, 2012
296
//see QQmlComponent::beginCreate for explanation of indestructible
Sep 29, 2011
Sep 29, 2011
297
ddata->indestructible = true;
Mar 23, 2012
Mar 23, 2012
298
ddata->explicitIndestructibleSet = true;
Sep 29, 2011
Sep 29, 2011
299
300
301
q->setInitialState(result);
}
Oct 6, 2011
Oct 6, 2011
302
303
304
if (watcher.hasRecursed())
return;
Sep 29, 2011
Sep 29, 2011
305
if (errors.isEmpty())
Feb 24, 2012
Feb 24, 2012
306
progress = QQmlIncubatorPrivate::Completing;
Sep 29, 2011
Sep 29, 2011
307
else
Feb 24, 2012
Feb 24, 2012
308
progress = QQmlIncubatorPrivate::Completed;
Sep 29, 2011
Sep 29, 2011
309
Oct 14, 2011
Oct 14, 2011
310
changeStatus(calculateStatus());
Sep 29, 2011
Sep 29, 2011
311
Oct 6, 2011
Oct 6, 2011
312
313
314
if (watcher.hasRecursed())
return;
Sep 29, 2011
Sep 29, 2011
315
316
317
318
if (i.shouldInterrupt())
goto finishIncubate;
}
Feb 24, 2012
Feb 24, 2012
319
if (progress == QQmlIncubatorPrivate::Completing) {
Sep 29, 2011
Sep 29, 2011
320
do {
Oct 6, 2011
Oct 6, 2011
321
322
323
if (watcher.hasRecursed())
return;
Feb 24, 2012
Feb 24, 2012
324
QQmlContextData *ctxt = vme.complete(i);
Nov 1, 2011
Nov 1, 2011
325
326
if (ctxt) {
rootContext = ctxt;
Feb 24, 2012
Feb 24, 2012
327
progress = QQmlIncubatorPrivate::Completed;
Sep 29, 2011
Sep 29, 2011
328
329
330
331
332
333
goto finishIncubate;
}
} while (!i.shouldInterrupt());
}
finishIncubate:
Feb 24, 2012
Feb 24, 2012
334
335
if (progress == QQmlIncubatorPrivate::Completed && waitingFor.isEmpty()) {
typedef QQmlIncubatorPrivate IP;
Oct 20, 2011
Oct 20, 2011
336
Feb 24, 2012
Feb 24, 2012
337
QQmlIncubatorPrivate *isWaiting = waitingOnMe;
Sep 29, 2011
Sep 29, 2011
338
339
clear();
Oct 20, 2011
Oct 20, 2011
340
341
342
343
344
345
346
347
if (isWaiting) {
QRecursionWatcher<IP, &IP::recursion> watcher(isWaiting);
changeStatus(calculateStatus());
if (!watcher.hasRecursed())
isWaiting->incubate(i);
} else {
changeStatus(calculateStatus());
}
Sep 29, 2011
Sep 29, 2011
348
Oct 20, 2011
Oct 20, 2011
349
enginePriv->inProgressCreations--;
Sep 29, 2011
Sep 29, 2011
350
351
352
353
354
355
356
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
enginePriv->warning(enginePriv->erroredBindings->error);
enginePriv->erroredBindings->removeError();
}
}
Oct 3, 2011
Oct 3, 2011
357
358
} else {
vmeGuard.guard(&vme);
Sep 29, 2011
Sep 29, 2011
359
360
361
}
}
Sep 29, 2011
Sep 29, 2011
362
363
364
/*!
Incubate objects for \a msecs, or until there are no more objects to incubate.
*/
Feb 24, 2012
Feb 24, 2012
365
void QQmlIncubationController::incubateFor(int msecs)
Sep 29, 2011
Sep 29, 2011
366
367
368
369
{
if (!d || d->incubatorCount == 0)
return;
Feb 24, 2012
Feb 24, 2012
370
QQmlVME::Interrupt i(msecs * 1000000);
Sep 29, 2011
Sep 29, 2011
371
372
i.reset();
do {
Feb 24, 2012
Feb 24, 2012
373
QQmlIncubatorPrivate *p = (QQmlIncubatorPrivate*)d->incubatorList.first();
Sep 29, 2011
Sep 29, 2011
374
375
376
377
p->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
}
Sep 29, 2011
Sep 29, 2011
378
379
/*!
Incubate objects while the bool pointed to by \a flag is true, or until there are no
Feb 28, 2012
Feb 28, 2012
380
more objects to incubate, or up to msecs if msecs is not zero.
Sep 29, 2011
Sep 29, 2011
381
382
383
384
Generally this method is used in conjunction with a thread or a UNIX signal that sets
the bool pointed to by \a flag to false when it wants incubation to be interrupted.
*/
Mar 5, 2012
Mar 5, 2012
385
void QQmlIncubationController::incubateWhile(volatile bool *flag, int msecs)
Sep 29, 2011
Sep 29, 2011
386
387
388
389
{
if (!d || d->incubatorCount == 0)
return;
Mar 5, 2012
Mar 5, 2012
390
QQmlVME::Interrupt i(flag, msecs * 1000000);
Feb 28, 2012
Feb 28, 2012
391
i.reset();
Sep 29, 2011
Sep 29, 2011
392
do {
Feb 24, 2012
Feb 24, 2012
393
QQmlIncubatorPrivate *p = (QQmlIncubatorPrivate*)d->incubatorList.first();
Sep 29, 2011
Sep 29, 2011
394
395
396
397
p->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
}
Sep 29, 2011
Sep 29, 2011
398
/*!
Feb 24, 2012
Feb 24, 2012
399
400
\class QQmlIncubator
\brief The QQmlIncubator class allows QML objects to be created asynchronously.
Sep 29, 2011
Sep 29, 2011
401
402
403
Creating QML objects - like delegates in a view, or a new page in an application - can take
a noticable amount of time, especially on resource constrained mobile devices. When an
Feb 24, 2012
Feb 24, 2012
404
application uses QQmlComponent::create() directly, the QML object instance is created
Sep 29, 2011
Sep 29, 2011
405
406
407
synchronously which, depending on the complexity of the object, can cause noticable pauses or
stutters in the application.
Feb 24, 2012
Feb 24, 2012
408
The use of QQmlIncubator gives more control over the creation of a QML object,
Sep 29, 2011
Sep 29, 2011
409
including allowing it to be created asynchronously using application idle time. The following
Feb 24, 2012
Feb 24, 2012
410
example shows a simple use of QQmlIncubator.
Sep 29, 2011
Sep 29, 2011
411
412
\code
Feb 24, 2012
Feb 24, 2012
413
QQmlIncubator incubator;
Sep 29, 2011
Sep 29, 2011
414
415
416
417
418
419
420
421
422
component->create(incubator);
while (incubator.isReady()) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
}
QObject *object = incubator.object();
\endcode
Feb 24, 2012
Feb 24, 2012
423
424
Asynchronous incubators are controlled by a QQmlIncubationController that is
set on the QQmlEngine, which lets the engine know when the application is idle and
Sep 29, 2011
Sep 29, 2011
425
incubating objects should be processed. If an incubation controller is not set on the
Feb 24, 2012
Feb 24, 2012
426
QQmlEngine, QQmlIncubator creates objects synchronously regardless of the
Sep 29, 2011
Sep 29, 2011
427
428
specified IncubationMode.
Feb 24, 2012
Feb 24, 2012
429
QQmlIncubator supports three incubation modes:
Sep 29, 2011
Sep 29, 2011
430
\list
Mar 13, 2012
Mar 13, 2012
431
\li Synchronous The creation occurs synchronously. That is, once the
Feb 24, 2012
Feb 24, 2012
432
QQmlComponent::create() call returns, the incubator will already be in either the
Sep 29, 2011
Sep 29, 2011
433
Error or Ready state. A synchronous incubator has no real advantage compared to using
Feb 24, 2012
Feb 24, 2012
434
the synchronous creation methods on QQmlComponent directly, but it may simplify an
Sep 29, 2011
Sep 29, 2011
435
436
437
application's implementation to use the same API for both synchronous and asynchronous
creations.
Mar 13, 2012
Mar 13, 2012
438
\li Asynchronous (default) The creation occurs asynchronously, assuming a
Feb 24, 2012
Feb 24, 2012
439
QQmlIncubatorController is set on the QQmlEngine.
Sep 29, 2011
Sep 29, 2011
440
441
442
443
444
445
446
The incubator will remain in the Loading state until either the creation is complete or an error
occurs. The statusChanged() callback can be used to be notified of status changes.
Applications should use the Asynchronous incubation mode to create objects that are not needed
immediately. For example, the ListView element uses Asynchronous incubation to create objects
that are slightly off screen while the list is being scrolled. If, during asynchronous creation,
Feb 24, 2012
Feb 24, 2012
447
the object is needed immediately the QQmlIncubator::forceCompletion() method can be called
Sep 29, 2011
Sep 29, 2011
448
449
to complete the creation process synchronously.
Mar 13, 2012
Mar 13, 2012
450
\li AsynchronousIfNested The creation will occur asynchronously if part of a nested asynchronous
Sep 29, 2011
Sep 29, 2011
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
creation, or synchronously if not.
In most scenarios where a QML element or component wants the appearance of a synchronous
instantiation, it should use this mode.
This mode is best explained with an example. When the ListView element is first created, it needs
to populate itself with an initial set of delegates to show. If the ListView was 400 pixels high,
and each delegate was 100 pixels high, it would need to create four initial delegate instances. If
the ListView used the Asynchronous incubation mode, the ListView would always be created empty and
then, sometime later, the four initial elements would appear.
Conversely, if the ListView was to use the Synchronous incubation mode it would behave correctly
but it may introduce stutters into the application. As QML would have to stop and instantiate the
ListView's delegates synchronously, if the ListView was part of a QML component that was being
instantiated asynchronously this would undo much of the benefit of asynchronous instantiation.
The AsynchronousIfNested mode reconciles this problem. By using AsynchronousIfNested, the ListView
delegates are instantiated asynchronously if the ListView itself is already part of an asynchronous
instantiation, and synchronously otherwise. In the case of a nested asynchronous instantiation, the
outer asynchronous instantiation will not complete until after all the nested instantiations have also
completed. This ensures that by the time the outer asynchronous instantitation completes, inner
elements like ListView have already completed loading their initial delegates.
It is almost always incorrect to use the Synchronous incubation mode - elements or components that
want the appearance of synchronous instantiation, but without the downsides of introducing freezes
or stutters into the application, should use the AsynchronousIfNested incubation mode.
\endlist
*/
/*!
Create a new incubator with the specified \a mode
*/
Feb 24, 2012
Feb 24, 2012
483
484
QQmlIncubator::QQmlIncubator(IncubationMode mode)
: d(new QQmlIncubatorPrivate(this, mode))
Sep 29, 2011
Sep 29, 2011
485
486
487
{
}
Sep 29, 2011
Sep 29, 2011
488
/*! \internal */
Feb 24, 2012
Feb 24, 2012
489
QQmlIncubator::~QQmlIncubator()
Sep 29, 2011
Sep 29, 2011
490
{
Oct 3, 2011
Oct 3, 2011
491
492
clear();
Sep 29, 2011
Sep 29, 2011
493
494
495
delete d; d = 0;
}
Sep 29, 2011
Sep 29, 2011
496
/*!
Feb 24, 2012
Feb 24, 2012
497
\enum QQmlIncubator::IncubationMode
Sep 29, 2011
Sep 29, 2011
498
499
Specifies the mode the incubator operates in. Regardless of the incubation mode, a
Feb 24, 2012
Feb 24, 2012
500
501
QQmlIncubator will behave synchronously if the QQmlEngine does not have
a QQmlIncubationController set.
Sep 29, 2011
Sep 29, 2011
502
503
504
505
506
507
508
509
510
511
\value Asynchronous The object will be created asynchronously.
\value AsynchronousIfNested If the object is being created in a context that is already part
of an asynchronous creation, this incubator will join that existing incubation and execute
asynchronously. The existing incubation will not become Ready until both it and this
incubation have completed. Otherwise, the incubation will execute synchronously.
\value Synchronous The object will be created synchronously.
*/
/*!
Feb 24, 2012
Feb 24, 2012
512
\enum QQmlIncubator::Status
Sep 29, 2011
Sep 29, 2011
513
Feb 24, 2012
Feb 24, 2012
514
Specifies the status of the QQmlIncubator.
Sep 29, 2011
Sep 29, 2011
515
Feb 24, 2012
Feb 24, 2012
516
\value Null Incubation is not in progress. Call QQmlComponent::create() to begin incubating.
Sep 29, 2011
Sep 29, 2011
517
518
519
520
521
522
523
524
525
\value Ready The object is fully created and can be accessed by calling object().
\value Loading The object is in the process of being created.
\value Error An error occurred. The errors can be access by calling errors().
*/
/*!
Clears the incubator. Any in-progress incubation is aborted. If the incubator is in the
Ready state, the created object is \b not deleted.
*/
Feb 24, 2012
Feb 24, 2012
526
void QQmlIncubator::clear()
Sep 29, 2011
Sep 29, 2011
527
{
Feb 24, 2012
Feb 24, 2012
528
typedef QQmlIncubatorPrivate IP;
Oct 6, 2011
Oct 6, 2011
529
530
QRecursionWatcher<IP, &IP::recursion> watcher(d);
Sep 30, 2011
Sep 30, 2011
531
532
533
534
535
Status s = status();
if (s == Null)
return;
Feb 24, 2012
Feb 24, 2012
536
QQmlEnginePrivate *enginePriv = 0;
Oct 4, 2011
Oct 4, 2011
537
538
if (s == Loading) {
Q_ASSERT(d->component);
Feb 24, 2012
Feb 24, 2012
539
enginePriv = QQmlEnginePrivate::get(d->component->engine);
Oct 6, 2011
Oct 6, 2011
540
if (d->result) d->result->deleteLater();
Oct 6, 2011
Oct 6, 2011
541
d->result = 0;
Oct 4, 2011
Oct 4, 2011
542
543
}
Oct 3, 2011
Oct 3, 2011
544
545
d->clear();
Mar 19, 2012
Mar 19, 2012
546
547
548
549
// if we're waiting on any incubators then they should be cleared too.
while (d->waitingFor.first())
static_cast<QQmlIncubatorPrivate*>(d->waitingFor.first())->q->clear();
Oct 3, 2011
Oct 3, 2011
550
551
552
d->vme.reset();
d->vmeGuard.clear();
Sep 30, 2011
Sep 30, 2011
553
554
555
556
557
558
Q_ASSERT(d->component == 0);
Q_ASSERT(d->waitingOnMe == 0);
Q_ASSERT(d->waitingFor.isEmpty());
Q_ASSERT(!d->nextWaitingFor.isInList());
d->errors.clear();
Feb 24, 2012
Feb 24, 2012
559
d->progress = QQmlIncubatorPrivate::Execute;
Sep 30, 2011
Sep 30, 2011
560
d->result = 0;
Oct 4, 2011
Oct 4, 2011
561
562
563
564
565
566
567
568
569
570
571
572
573
if (s == Loading) {
Q_ASSERT(enginePriv);
enginePriv->inProgressCreations--;
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
enginePriv->warning(enginePriv->erroredBindings->error);
enginePriv->erroredBindings->removeError();
}
}
}
Oct 14, 2011
Oct 14, 2011
574
d->changeStatus(Null);
Sep 29, 2011
Sep 29, 2011
575
576
}
Sep 29, 2011
Sep 29, 2011
577
578
579
580
/*!
Force any in-progress incubation to finish synchronously. Once this call
returns, the incubator will not be in the Loading state.
*/
Feb 24, 2012
Feb 24, 2012
581
void QQmlIncubator::forceCompletion()
Sep 29, 2011
Sep 29, 2011
582
{
Feb 24, 2012
Feb 24, 2012
583
QQmlVME::Interrupt i;
Sep 29, 2011
Sep 29, 2011
584
585
while (Loading == status()) {
while (Loading == status() && !d->waitingFor.isEmpty())
Feb 24, 2012
Feb 24, 2012
586
static_cast<QQmlIncubatorPrivate *>(d->waitingFor.first())->incubate(i);
Sep 29, 2011
Sep 29, 2011
587
588
589
590
591
if (Loading == status())
d->incubate(i);
}
}
Sep 29, 2011
Sep 29, 2011
592
593
594
/*!
Returns true if the incubator's status() is Null.
*/
Feb 24, 2012
Feb 24, 2012
595
bool QQmlIncubator::isNull() const
Sep 29, 2011
Sep 29, 2011
596
597
598
599
{
return status() == Null;
}
Sep 29, 2011
Sep 29, 2011
600
601
602
/*!
Returns true if the incubator's status() is Ready.
*/
Feb 24, 2012
Feb 24, 2012
603
bool QQmlIncubator::isReady() const
Sep 29, 2011
Sep 29, 2011
604
605
606
607
{
return status() == Ready;
}
Sep 29, 2011
Sep 29, 2011
608
609
610
/*!
Returns true if the incubator's status() is Error.
*/
Feb 24, 2012
Feb 24, 2012
611
bool QQmlIncubator::isError() const
Sep 29, 2011
Sep 29, 2011
612
613
614
615
{
return status() == Error;
}
Sep 29, 2011
Sep 29, 2011
616
617
618
/*!
Returns true if the incubator's status() is Loading.
*/
Feb 24, 2012
Feb 24, 2012
619
bool QQmlIncubator::isLoading() const
Sep 29, 2011
Sep 29, 2011
620
621
622
623
{
return status() == Loading;
}
Sep 29, 2011
Sep 29, 2011
624
625
626
/*!
Return the list of errors encountered while incubating the object.
*/
Feb 24, 2012
Feb 24, 2012
627
QList<QQmlError> QQmlIncubator::errors() const
Sep 29, 2011
Sep 29, 2011
628
629
630
631
{
return d->errors;
}
Sep 29, 2011
Sep 29, 2011
632
/*!
Feb 24, 2012
Feb 24, 2012
633
Return the incubation mode passed to the QQmlIncubator constructor.
Sep 29, 2011
Sep 29, 2011
634
*/
Feb 24, 2012
Feb 24, 2012
635
QQmlIncubator::IncubationMode QQmlIncubator::incubationMode() const
Sep 29, 2011
Sep 29, 2011
636
637
638
639
{
return d->mode;
}
Sep 29, 2011
Sep 29, 2011
640
641
642
/*!
Return the current status of the incubator.
*/
Feb 24, 2012
Feb 24, 2012
643
QQmlIncubator::Status QQmlIncubator::status() const
Sep 29, 2011
Sep 29, 2011
644
{
Oct 14, 2011
Oct 14, 2011
645
return d->status;
Sep 29, 2011
Sep 29, 2011
646
647
}
Sep 29, 2011
Sep 29, 2011
648
649
650
/*!
Return the incubated object if the status is Ready, otherwise 0.
*/
Feb 24, 2012
Feb 24, 2012
651
QObject *QQmlIncubator::object() const
Sep 29, 2011
Sep 29, 2011
652
653
654
655
656
{
if (status() != Ready) return 0;
else return d->result;
}
Sep 29, 2011
Sep 29, 2011
657
658
659
660
661
/*!
Called when the status of the incubator changes. \a status is the new status.
The default implementation does nothing.
*/
Feb 24, 2012
Feb 24, 2012
662
void QQmlIncubator::statusChanged(Status status)
Sep 29, 2011
Sep 29, 2011
663
{
Sep 29, 2011
Sep 29, 2011
664
Q_UNUSED(status);
Sep 29, 2011
Sep 29, 2011
665
666
}
Sep 29, 2011
Sep 29, 2011
667
668
/*!
Called after the object is first created, but before property bindings are
Feb 24, 2012
Feb 24, 2012
669
670
671
evaluated and, if applicable, QQmlParserStatus::componentComplete() is
called. This is equivalent to the point between QQmlComponent::beginCreate()
and QQmlComponent::endCreate(), and can be used to assign initial values
Sep 29, 2011
Sep 29, 2011
672
673
674
675
to the object's properties.
The default implementation does nothing.
*/
Feb 24, 2012
Feb 24, 2012
676
void QQmlIncubator::setInitialState(QObject *object)
Sep 29, 2011
Sep 29, 2011
677
{
Sep 29, 2011
Sep 29, 2011
678
Q_UNUSED(object);
Sep 29, 2011
Sep 29, 2011
679
}
Oct 14, 2011
Oct 14, 2011
680
Feb 24, 2012
Feb 24, 2012
681
void QQmlIncubatorPrivate::changeStatus(QQmlIncubator::Status s)
Oct 14, 2011
Oct 14, 2011
682
683
684
685
686
687
688
689
{
if (s == status)
return;
status = s;
q->statusChanged(status);
}
Feb 24, 2012
Feb 24, 2012
690
QQmlIncubator::Status QQmlIncubatorPrivate::calculateStatus() const
Oct 14, 2011
Oct 14, 2011
691
692
{
if (!errors.isEmpty())
Feb 24, 2012
Feb 24, 2012
693
694
return QQmlIncubator::Error;
else if (result && progress == QQmlIncubatorPrivate::Completed &&
Oct 14, 2011
Oct 14, 2011
695
waitingFor.isEmpty())
Feb 24, 2012
Feb 24, 2012
696
return QQmlIncubator::Ready;
Oct 14, 2011
Oct 14, 2011
697
else if (component)
Feb 24, 2012
Feb 24, 2012
698
return QQmlIncubator::Loading;
Oct 14, 2011
Oct 14, 2011
699
else
Feb 24, 2012
Feb 24, 2012
700
return QQmlIncubator::Null;
Oct 14, 2011
Oct 14, 2011
701
}