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