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