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

source code of qtdeclarative/src/qml/qml/qqmlincubator.cpp