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
4#include "qqmlcomponent.h"
5#include "qqmlcomponent_p.h"
6#include "qqmlcomponentattached_p.h"
7
8#include "qqmlengine_p.h"
9#include "qqmlvme_p.h"
10#include "qqml.h"
11#include "qqmlengine.h"
12#include "qqmlincubator.h"
13#include "qqmlincubator_p.h"
14#include <private/qqmljavascriptexpression_p.h>
15#include <private/qqmlsourcecoordinate_p.h>
16
17#include <private/qv4functionobject_p.h>
18#include <private/qv4script_p.h>
19#include <private/qv4scopedvalue_p.h>
20#include <private/qv4objectiterator_p.h>
21#include <private/qv4qobjectwrapper_p.h>
22#include <private/qv4jscall_p.h>
23
24#include <QDir>
25#include <QStack>
26#include <QStringList>
27#include <QThreadStorage>
28#include <QtCore/qdebug.h>
29#include <QtCore/qloggingcategory.h>
30#include <qqmlinfo.h>
31
32namespace {
33 Q_CONSTINIT thread_local int creationDepth = 0;
34}
35
36Q_LOGGING_CATEGORY(lcQmlComponentGeneral, "qt.qml.qmlcomponent")
37
38QT_BEGIN_NAMESPACE
39
40class QQmlComponentExtension : public QV4::ExecutionEngine::Deletable
41{
42public:
43 QQmlComponentExtension(QV4::ExecutionEngine *v4);
44 virtual ~QQmlComponentExtension();
45
46 QV4::PersistentValue incubationProto;
47};
48V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
49
50/*!
51 \class QQmlComponent
52 \since 5.0
53 \inmodule QtQml
54
55 \brief The QQmlComponent class encapsulates a QML component definition.
56
57 Components are reusable, encapsulated QML types with well-defined interfaces.
58
59 A QQmlComponent instance can be created from a QML file.
60 For example, if there is a \c main.qml file like this:
61
62 \qml
63 import QtQuick 2.0
64
65 Item {
66 width: 200
67 height: 200
68 }
69 \endqml
70
71 The following code loads this QML file as a component, creates an instance of
72 this component using create(), and then queries the \l Item's \l {Item::}{width}
73 value:
74
75 \code
76 QQmlEngine *engine = new QQmlEngine;
77 QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
78
79 QObject *myObject = component.create();
80 QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
81 int width = item->width(); // width = 200
82 \endcode
83
84 To create instances of a component in code where a QQmlEngine instance is
85 not available, you can use \l qmlContext() or \l qmlEngine(). For example,
86 in the scenario below, child items are being created within a QQuickItem
87 subclass:
88
89 \code
90 void MyCppItem::init()
91 {
92 QQmlEngine *engine = qmlEngine(this);
93 // Or:
94 // QQmlEngine *engine = qmlContext(this)->engine();
95 QQmlComponent component(engine, QUrl::fromLocalFile("MyItem.qml"));
96 QQuickItem *childItem = qobject_cast<QQuickItem*>(component.create());
97 childItem->setParentItem(this);
98 }
99 \endcode
100
101 Note that these functions will return \c null when called inside the
102 constructor of a QObject subclass, as the instance will not yet have
103 a context nor engine.
104
105 \section2 Network Components
106
107 If the URL passed to QQmlComponent is a network resource, or if the QML document references a
108 network resource, the QQmlComponent has to fetch the network data before it is able to create
109 objects. In this case, the QQmlComponent will have a \l {QQmlComponent::Loading}{Loading}
110 \l {QQmlComponent::status()}{status}. An application will have to wait until the component
111 is \l {QQmlComponent::Ready}{Ready} before calling \l {QQmlComponent::create()}.
112
113 The following example shows how to load a QML file from a network resource. After creating
114 the QQmlComponent, it tests whether the component is loading. If it is, it connects to the
115 QQmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
116 directly. Note that QQmlComponent::isLoading() may be false for a network component if the
117 component has been cached and is ready immediately.
118
119 \code
120 MyApplication::MyApplication()
121 {
122 // ...
123 component = new QQmlComponent(engine, QUrl("http://www.example.com/main.qml"));
124 if (component->isLoading()) {
125 QObject::connect(component, &QQmlComponent::statusChanged,
126 this, &MyApplication::continueLoading);
127 } else {
128 continueLoading();
129 }
130 }
131
132 void MyApplication::continueLoading()
133 {
134 if (component->isError()) {
135 qWarning() << component->errors();
136 } else {
137 QObject *myObject = component->create();
138 }
139 }
140 \endcode
141*/
142
143/*!
144 \qmltype Component
145 \instantiates QQmlComponent
146 \ingroup qml-utility-elements
147 \inqmlmodule QtQml
148 \brief Encapsulates a QML component definition.
149
150 Components are reusable, encapsulated QML types with well-defined interfaces.
151
152 Components are often defined by \l {{QML Documents}}{component files} -
153 that is, \c .qml files. The \e Component type essentially allows QML components
154 to be defined inline, within a \l {QML Documents}{QML document}, rather than as a separate QML file.
155 This may be useful for reusing a small component within a QML file, or for defining
156 a component that logically belongs with other QML components within a file.
157
158 For example, here is a component that is used by multiple \l Loader objects.
159 It contains a single item, a \l Rectangle:
160
161 \snippet qml/component.qml 0
162
163 Notice that while a \l Rectangle by itself would be automatically
164 rendered and displayed, this is not the case for the above rectangle
165 because it is defined inside a \c Component. The component encapsulates the
166 QML types within, as if they were defined in a separate QML
167 file, and is not loaded until requested (in this case, by the
168 two \l Loader objects). Because Component is not derived from Item, you cannot
169 anchor anything to it.
170
171 Defining a \c Component is similar to defining a \l {QML Documents}{QML document}.
172 A QML document has a single top-level item that defines the behavior and
173 properties of that component, and cannot define properties or behavior outside
174 of that top-level item. In the same way, a \c Component definition contains a single
175 top level item (which in the above example is a \l Rectangle) and cannot define any
176 data outside of this item, with the exception of an \e id (which in the above example
177 is \e redSquare).
178
179 The \c Component type is commonly used to provide graphical components
180 for views. For example, the ListView::delegate property requires a \c Component
181 to specify how each list item is to be displayed.
182
183 \c Component objects can also be created dynamically using
184 \l{QtQml::Qt::createComponent()}{Qt.createComponent()}.
185
186 \section2 Creation Context
187
188 The creation context of a Component corresponds to the context where the Component was declared.
189 This context is used as the parent context (creating a \l{qtqml-documents-scope.html#component-instance-hierarchy}{context hierarchy})
190 when the component is instantiated by an object such as a ListView or a Loader.
191
192 In the following example, \c comp1 is created within the root context of MyItem.qml, and any objects
193 instantiated from this component will have access to the ids and properties within that context,
194 such as \c internalSettings.color. When \c comp1 is used as a ListView delegate in another context
195 (as in main.qml below), it will continue to have access to the properties of its creation context
196 (which would otherwise be private to external users).
197
198 \table
199 \row
200 \li MyItem.qml
201 \li \snippet qml/component/MyItem.qml 0
202 \row
203 \li main.qml
204 \li \snippet qml/component/main.qml 0
205 \endtable
206
207 It is important that the lifetime of the creation context outlive any created objects. See
208 \l{Maintaining Dynamically Created Objects} for more details.
209*/
210
211/*!
212 \qmlattachedsignal Component::completed()
213
214 Emitted after the object has been instantiated. This can be used to
215 execute script code at startup, once the full QML environment has been
216 established.
217
218 The \c onCompleted signal handler can be declared on any object. The order
219 of running the handlers is undefined.
220
221 \qml
222 Rectangle {
223 Component.onCompleted: console.log("Completed Running!")
224 Rectangle {
225 Component.onCompleted: console.log("Nested Completed Running!")
226 }
227 }
228 \endqml
229*/
230
231/*!
232 \qmlattachedsignal Component::destruction()
233
234 Emitted as the object begins destruction. This can be used to undo
235 work done in response to the \l {completed}{completed()} signal, or other
236 imperative code in your application.
237
238 The \c onDestruction signal handler can be declared on any object. The
239 order of running the handlers is undefined.
240
241 \qml
242 Rectangle {
243 Component.onDestruction: console.log("Destruction Beginning!")
244 Rectangle {
245 Component.onDestruction: console.log("Nested Destruction Beginning!")
246 }
247 }
248 \endqml
249
250 \sa {Qt QML}
251*/
252
253/*!
254 \enum QQmlComponent::Status
255
256 Specifies the loading status of the QQmlComponent.
257
258 \value Null This QQmlComponent has no data. Call loadUrl() or setData() to add QML content.
259 \value Ready This QQmlComponent is ready and create() may be called.
260 \value Loading This QQmlComponent is loading network data.
261 \value Error An error has occurred. Call errors() to retrieve a list of \l {QQmlError}{errors}.
262*/
263
264/*!
265 \enum QQmlComponent::CompilationMode
266
267 Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
268
269 \value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
270 This is not always possible; for example, remote URLs will always load asynchronously.
271 \value Asynchronous Load/compile the component in a background thread.
272*/
273
274void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
275{
276 Q_Q(QQmlComponent);
277
278 Q_ASSERT(typeData);
279
280 fromTypeData(data: typeData);
281 typeData.reset();
282 progress = 1.0;
283
284 emit q->statusChanged(q->status());
285 emit q->progressChanged(progress);
286}
287
288void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
289{
290 Q_Q(QQmlComponent);
291
292 progress = p;
293
294 emit q->progressChanged(p);
295}
296
297void QQmlComponentPrivate::fromTypeData(const QQmlRefPointer<QQmlTypeData> &data)
298{
299 url = data->finalUrl();
300 compilationUnit.reset(t: data->compilationUnit());
301
302 if (!compilationUnit) {
303 Q_ASSERT(data->isError());
304 state.errors.clear();
305 state.appendErrors(qmlErrors: data->errors());
306 }
307}
308
309bool QQmlComponentPrivate::hadTopLevelRequiredProperties() const
310{
311 return state.creator()->componentHadTopLevelRequiredProperties();
312}
313
314void QQmlComponentPrivate::clear()
315{
316 if (typeData) {
317 typeData->unregisterCallback(this);
318 typeData.reset();
319 }
320
321 compilationUnit.reset();
322 loadedType = {};
323 inlineComponentName.reset();
324}
325
326QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *context)
327{
328 if (!engine) {
329 // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
330 qWarning(msg: "QQmlComponent: Must provide an engine before calling create");
331 return nullptr;
332 }
333 if (!context)
334 context = engine->rootContext();
335 return q->beginCreate(context);
336}
337
338static void removePendingQPropertyBinding(
339 QV4::Value *object, const QString &propertyName, QQmlObjectCreator *creator)
340{
341 if (!creator)
342 return;
343
344 QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>();
345 if (!wrapper)
346 return;
347
348 QObject *o = wrapper->object();
349 if (!o)
350 return;
351
352 if (QQmlData *ddata = QQmlData::get(object: o)) {
353 const QQmlPropertyData *propData = ddata->propertyCache->property(
354 key: propertyName, object: o, context: ddata->outerContext);
355 if (propData && propData->isBindable())
356 creator->removePendingBinding(target: o, propertyIndex: propData->coreIndex());
357 return;
358 }
359
360 const QMetaObject *meta = o->metaObject();
361 Q_ASSERT(meta);
362 const int index = meta->indexOfProperty(name: propertyName.toUtf8());
363 if (index != -1 && meta->property(index).isBindable())
364 creator->removePendingBinding(target: o, propertyIndex: index);
365}
366
367bool QQmlComponentPrivate::setInitialProperty(
368 QObject *base, const QString &name, const QVariant &value)
369{
370 const QStringList properties = name.split(sep: u'.');
371
372 if (properties.size() > 1) {
373 QV4::Scope scope(engine->handle());
374 QV4::ScopedObject object(scope, QV4::QObjectWrapper::wrap(engine: scope.engine, object: base));
375 QV4::ScopedString segment(scope);
376
377 for (int i = 0; i < properties.size() - 1; ++i) {
378 segment = scope.engine->newString(s: properties.at(i));
379 object = object->get(name: segment);
380 if (scope.engine->hasException)
381 break;
382 }
383 const QString lastProperty = properties.last();
384 segment = scope.engine->newString(s: lastProperty);
385 object->put(name: segment, v: scope.engine->metaTypeToJS(type: value.metaType(), data: value.constData()));
386 if (scope.engine->hasException) {
387 qmlWarning(me: base, error: scope.engine->catchExceptionAsQmlError());
388 scope.engine->hasException = false;
389 return false;
390 }
391
392 removePendingQPropertyBinding(object, propertyName: lastProperty, creator: state.creator());
393 return true;
394 }
395
396 QQmlProperty prop;
397 if (state.hasUnsetRequiredProperties())
398 prop = QQmlComponentPrivate::removePropertyFromRequired(
399 createdComponent: base, name, requiredProperties: state.requiredProperties(), engine);
400 else
401 prop = QQmlProperty(base, name, engine);
402 QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(p: prop);
403 const bool isValid = prop.isValid();
404 if (isValid && privProp->writeValueProperty(value, {})) {
405 if (prop.isBindable()) {
406 if (QQmlObjectCreator *creator = state.creator())
407 creator->removePendingBinding(target: prop.object(), propertyIndex: prop.index());
408 }
409 } else {
410 QQmlError error{};
411 error.setUrl(url);
412 if (isValid) {
413 error.setDescription(QStringLiteral("Could not set initial property %1").arg(a: name));
414 } else {
415 error.setDescription(QStringLiteral("Setting initial properties failed: "
416 "%2 does not have a property called %1")
417 .arg(args: name, args: QQmlMetaType::prettyTypeName(object: base)));
418 }
419 qmlWarning(me: base, error);
420 return false;
421 }
422
423 return true;
424
425}
426
427/*!
428 \internal
429*/
430QQmlComponent::QQmlComponent(QObject *parent)
431 : QObject(*(new QQmlComponentPrivate), parent)
432{
433}
434
435/*!
436 Destruct the QQmlComponent.
437*/
438QQmlComponent::~QQmlComponent()
439{
440 Q_D(QQmlComponent);
441
442 if (d->state.isCompletePending()) {
443 qWarning(msg: "QQmlComponent: Component destroyed while completion pending");
444
445 if (isError()) {
446 qWarning() << "This may have been caused by one of the following errors:";
447 for (const QQmlComponentPrivate::AnnotatedQmlError &e : std::as_const(t&: d->state.errors))
448 qWarning().nospace().noquote() << QLatin1String(" ") << e.error;
449 }
450
451 // we might not have the creator anymore if the engine is gone
452 if (d->state.hasCreator())
453 d->completeCreate();
454 }
455
456 if (d->typeData) {
457 d->typeData->unregisterCallback(d);
458 d->typeData.reset();
459 }
460}
461
462/*!
463 \qmlproperty enumeration Component::status
464
465 This property holds the status of component loading. The status can be one of the
466 following:
467
468 \value Component.Null no data is available for the component
469 \value Component.Ready the component has been loaded, and can be used to create instances.
470 \value Component.Loading the component is currently being loaded
471 \value Component.Error an error occurred while loading the component.
472 Calling \l errorString() will provide a human-readable description of any errors.
473 */
474
475/*!
476 \property QQmlComponent::status
477 The component's current \l{QQmlComponent::Status} {status}.
478 */
479QQmlComponent::Status QQmlComponent::status() const
480{
481 Q_D(const QQmlComponent);
482
483 if (d->typeData)
484 return Loading;
485 else if (!d->state.errors.isEmpty())
486 return Error;
487 else if (d->engine && (d->compilationUnit || d->loadedType.isValid()))
488 return Ready;
489 else
490 return Null;
491}
492
493/*!
494 Returns true if status() == QQmlComponent::Null.
495*/
496bool QQmlComponent::isNull() const
497{
498 return status() == Null;
499}
500
501/*!
502 Returns true if status() == QQmlComponent::Ready.
503*/
504bool QQmlComponent::isReady() const
505{
506 return status() == Ready;
507}
508
509/*!
510 Returns true if status() == QQmlComponent::Error.
511*/
512bool QQmlComponent::isError() const
513{
514 return status() == Error;
515}
516
517/*!
518 Returns true if status() == QQmlComponent::Loading.
519*/
520bool QQmlComponent::isLoading() const
521{
522 return status() == Loading;
523}
524
525/*!
526 Returns true if the component was created in a QML files that specifies
527 \c{pragma ComponentBehavior: Bound}, otherwise returns false.
528
529 \since 6.5
530 */
531bool QQmlComponent::isBound() const
532{
533 Q_D(const QQmlComponent);
534 return d->isBound();
535}
536
537/*!
538 \qmlproperty real Component::progress
539 The progress of loading the component, from 0.0 (nothing loaded)
540 to 1.0 (finished).
541*/
542
543/*!
544 \property QQmlComponent::progress
545 The progress of loading the component, from 0.0 (nothing loaded)
546 to 1.0 (finished).
547*/
548qreal QQmlComponent::progress() const
549{
550 Q_D(const QQmlComponent);
551 return d->progress;
552}
553
554/*!
555 \fn void QQmlComponent::progressChanged(qreal progress)
556
557 Emitted whenever the component's loading progress changes. \a progress will be the
558 current progress between 0.0 (nothing loaded) and 1.0 (finished).
559*/
560
561/*!
562 \fn void QQmlComponent::statusChanged(QQmlComponent::Status status)
563
564 Emitted whenever the component's status changes. \a status will be the
565 new status.
566*/
567
568/*!
569 Create a QQmlComponent with no data and give it the specified
570 \a engine and \a parent. Set the data with setData().
571*/
572QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
573 : QObject(*(new QQmlComponentPrivate), parent)
574{
575 Q_D(QQmlComponent);
576 d->engine = engine;
577 QObject::connect(sender: engine, signal: &QObject::destroyed, context: this, slot: [d]() {
578 d->state.clear();
579 d->engine = nullptr;
580 });
581}
582
583/*!
584 Create a QQmlComponent from the given \a url and give it the
585 specified \a parent and \a engine.
586
587 \include qqmlcomponent.qdoc url-note
588
589 \sa loadUrl()
590*/
591QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent)
592 : QQmlComponent(engine, url, QQmlComponent::PreferSynchronous, parent)
593{
594}
595
596/*!
597 Create a QQmlComponent from the given \a url and give it the
598 specified \a parent and \a engine. If \a mode is \l Asynchronous,
599 the component will be loaded and compiled asynchronously.
600
601 \include qqmlcomponent.qdoc url-note
602
603 \sa loadUrl()
604*/
605QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode,
606 QObject *parent)
607 : QQmlComponent(engine, parent)
608{
609 Q_D(QQmlComponent);
610 d->loadUrl(newUrl: url, mode);
611}
612
613/*!
614 Create a QQmlComponent from the given \a uri and \a typeName and give it
615 the specified \a parent and \a engine. If possible, the component will
616 be loaded synchronously.
617
618 \sa loadFromModule()
619 \since 6.5
620 \overload
621*/
622QQmlComponent::QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, QObject *parent)
623 : QQmlComponent(engine, uri, typeName, QQmlComponent::PreferSynchronous, parent)
624{
625
626}
627
628/*!
629 Create a QQmlComponent from the given \a uri and \a typeName and give it
630 the specified \a parent and \a engine. If \a mode is \l Asynchronous,
631 the component will be loaded and compiled asynchronously.
632
633 \sa loadFromModule()
634 \since 6.5
635 \overload
636*/
637QQmlComponent::QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, CompilationMode mode, QObject *parent)
638 : QQmlComponent(engine, parent)
639{
640 loadFromModule(uri, typeName, mode);
641}
642
643/*!
644 Create a QQmlComponent from the given \a fileName and give it the specified
645 \a parent and \a engine.
646
647 \sa loadUrl()
648*/
649QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
650 QObject *parent)
651 : QQmlComponent(engine, fileName, QQmlComponent::PreferSynchronous, parent)
652{
653}
654
655/*!
656 Create a QQmlComponent from the given \a fileName and give it the specified
657 \a parent and \a engine. If \a mode is \l Asynchronous,
658 the component will be loaded and compiled asynchronously.
659
660 \sa loadUrl()
661*/
662QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
663 CompilationMode mode, QObject *parent)
664 : QQmlComponent(engine, parent)
665{
666 Q_D(QQmlComponent);
667 if (fileName.startsWith(c: u':'))
668 d->loadUrl(newUrl: QUrl(QLatin1String("qrc") + fileName), mode);
669 else if (QDir::isAbsolutePath(path: fileName))
670 d->loadUrl(newUrl: QUrl::fromLocalFile(localfile: fileName), mode);
671 else
672 d->loadUrl(newUrl: QUrl(fileName), mode);
673}
674
675/*!
676 \internal
677*/
678QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit,
679 int start, QObject *parent)
680 : QQmlComponent(engine, parent)
681{
682 Q_D(QQmlComponent);
683 d->compilationUnit.reset(t: compilationUnit);
684 d->start = start;
685 d->url = compilationUnit->finalUrl();
686 d->progress = 1.0;
687}
688
689/*!
690 Sets the QQmlComponent to use the given QML \a data. If \a url
691 is provided, it is used to set the component name and to provide
692 a base path for items resolved by this component.
693*/
694void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
695{
696 Q_D(QQmlComponent);
697
698 if (!d->engine) {
699 // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
700 qWarning(msg: "QQmlComponent: Must provide an engine before calling setData");
701 return;
702 }
703
704 d->clear();
705
706 d->url = url;
707
708 QQmlRefPointer<QQmlTypeData> typeData = QQmlEnginePrivate::get(e: d->engine)->typeLoader.getType(data, url);
709
710 if (typeData->isCompleteOrError()) {
711 d->fromTypeData(data: typeData);
712 } else {
713 d->typeData = typeData;
714 d->typeData->registerCallback(d);
715 }
716
717 d->progress = 1.0;
718 emit statusChanged(status());
719 emit progressChanged(d->progress);
720}
721
722/*!
723 Returns the QQmlContext the component was created in. This is only
724 valid for components created directly from QML.
725*/
726QQmlContext *QQmlComponent::creationContext() const
727{
728 Q_D(const QQmlComponent);
729 if (!d->creationContext.isNull())
730 return d->creationContext->asQQmlContext();
731
732 return qmlContext(this);
733}
734
735/*!
736 Returns the QQmlEngine of this component.
737
738 \since 5.12
739*/
740QQmlEngine *QQmlComponent::engine() const
741{
742 Q_D(const QQmlComponent);
743 return d->engine;
744}
745
746/*!
747 Load the QQmlComponent from the provided \a url.
748
749 \include qqmlcomponent.qdoc url-note
750*/
751void QQmlComponent::loadUrl(const QUrl &url)
752{
753 Q_D(QQmlComponent);
754 d->loadUrl(newUrl: url);
755}
756
757/*!
758 Load the QQmlComponent from the provided \a url.
759 If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously.
760
761 \include qqmlcomponent.qdoc url-note
762*/
763void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode)
764{
765 Q_D(QQmlComponent);
766 d->loadUrl(newUrl: url, mode);
767}
768
769void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode)
770{
771 Q_Q(QQmlComponent);
772 clear();
773
774 if (newUrl.isRelative()) {
775 // The new URL is a relative URL like QUrl("main.qml").
776 url = engine->baseUrl().resolved(relative: QUrl(newUrl.toString()));
777 } else if (engine->baseUrl().isLocalFile() && newUrl.isLocalFile() && !QDir::isAbsolutePath(path: newUrl.toLocalFile())) {
778 // The new URL is a file on disk but it's a relative path; e.g.:
779 // QUrl::fromLocalFile("main.qml") or QUrl("file:main.qml")
780 // We need to remove the scheme so that it becomes a relative URL with a relative path:
781 QUrl fixedUrl(newUrl);
782 fixedUrl.setScheme(QString());
783 // Then, turn it into an absolute URL with an absolute path by resolving it against the engine's baseUrl().
784 // This is a compatibility hack for QTBUG-58837.
785 url = engine->baseUrl().resolved(relative: fixedUrl);
786 } else {
787 url = newUrl;
788 }
789
790 if (newUrl.isEmpty()) {
791 QQmlError error;
792 error.setDescription(QQmlComponent::tr(s: "Invalid empty URL"));
793 state.errors.emplaceBack(args&: error);
794 return;
795 }
796
797 if (progress != 0.0) {
798 progress = 0.0;
799 emit q->progressChanged(progress);
800 }
801
802 QQmlTypeLoader::Mode loaderMode = (mode == QQmlComponent::Asynchronous)
803 ? QQmlTypeLoader::Asynchronous
804 : QQmlTypeLoader::PreferSynchronous;
805 QQmlRefPointer<QQmlTypeData> data = QQmlEnginePrivate::get(e: engine)->typeLoader.getType(unNormalizedUrl: url, mode: loaderMode);
806
807 if (data->isCompleteOrError()) {
808 fromTypeData(data);
809 progress = 1.0;
810 } else {
811 typeData = data;
812 typeData->registerCallback(this);
813 progress = data->progress();
814 }
815
816 emit q->statusChanged(q->status());
817 if (progress != 0.0)
818 emit q->progressChanged(progress);
819}
820
821/*!
822 Returns the list of errors that occurred during the last compile or create
823 operation. An empty list is returned if isError() is not set.
824*/
825QList<QQmlError> QQmlComponent::errors() const
826{
827 Q_D(const QQmlComponent);
828 QList<QQmlError> errors;
829 errors.reserve(asize: d->state.errors.size());
830 for (const QQmlComponentPrivate::AnnotatedQmlError &annotated : d->state.errors)
831 errors.emplaceBack(args: annotated.error);
832 return errors;
833}
834
835/*!
836 \qmlmethod string Component::errorString()
837
838 Returns a human-readable description of any error.
839
840 The string includes the file, location, and description of each error.
841 If multiple errors are present, they are separated by a newline character.
842
843 If no errors are present, an empty string is returned.
844*/
845
846/*!
847 \internal
848 errorString() is only meant as a way to get the errors from QML side.
849*/
850QString QQmlComponent::errorString() const
851{
852 Q_D(const QQmlComponent);
853 QString ret;
854 if(!isError())
855 return ret;
856 for (const QQmlComponentPrivate::AnnotatedQmlError &annotated : d->state.errors) {
857 const QQmlError &e = annotated.error;
858 ret += e.url().toString() + QLatin1Char(':') +
859 QString::number(e.line()) + QLatin1Char(' ') +
860 e.description() + QLatin1Char('\n');
861 }
862 return ret;
863}
864
865/*!
866 \qmlproperty url Component::url
867 The component URL. This is the URL that was used to construct the component.
868*/
869
870/*!
871 \property QQmlComponent::url
872 The component URL. This is the URL passed to either the constructor,
873 or the loadUrl(), or setData() methods.
874*/
875QUrl QQmlComponent::url() const
876{
877 Q_D(const QQmlComponent);
878 return d->url;
879}
880
881/*!
882 \internal
883*/
884QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
885 : QObject(dd, parent)
886{
887}
888
889/*!
890 Create an object instance from this component, within the specified \a context.
891 Returns \nullptr if creation failed.
892
893 If \a context is \nullptr (the default), it will create the instance in the
894 \l {QQmlEngine::rootContext()}{root context} of the engine.
895
896 The ownership of the returned object instance is transferred to the caller.
897
898 If the object being created from this component is a visual item, it must
899 have a visual parent, which can be set by calling
900 QQuickItem::setParentItem(). See \l {Concepts - Visual Parent in Qt Quick}
901 for more details.
902
903 \sa QQmlEngine::ObjectOwnership
904*/
905QObject *QQmlComponent::create(QQmlContext *context)
906{
907 Q_D(QQmlComponent);
908 return d->createWithProperties(parent: nullptr, properties: QVariantMap {}, context);
909}
910
911/*!
912 Create an object instance of this component, within the specified \a context,
913 and initialize its top-level properties with \a initialProperties.
914
915 \omit
916 TODO: also mention errorString() when QTBUG-93239 is fixed
917 \endomit
918
919 If any of the \a initialProperties cannot be set, a warning is issued. If
920 there are unset required properties, the object creation fails and returns
921 \c nullptr, in which case \l isError() will return \c true.
922
923 \sa QQmlComponent::create
924 \since 5.14
925*/
926QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context)
927{
928 Q_D(QQmlComponent);
929 return d->createWithProperties(parent: nullptr, properties: initialProperties, context);
930}
931
932static void QQmlComponent_setQmlParent(QObject *me, QObject *parent); // forward declaration
933
934/*! \internal
935 */
936QObject *QQmlComponentPrivate::createWithProperties(QObject *parent, const QVariantMap &properties,
937 QQmlContext *context, CreateBehavior behavior)
938{
939 Q_Q(QQmlComponent);
940
941 QObject *rv = doBeginCreate(q, context);
942 if (!rv) {
943 if (state.isCompletePending()) {
944 // overridden completCreate might assume that
945 // the object has actually been created
946 ++creationDepth;
947 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(e: engine);
948 complete(enginePriv: ep, state: &state);
949 --creationDepth;
950 }
951 return nullptr;
952 }
953
954 QQmlComponent_setQmlParent(me: rv, parent); // internally checks if parent is nullptr
955
956 q->setInitialProperties(component: rv, properties);
957 q->completeCreate();
958
959 if (state.hasUnsetRequiredProperties()) {
960 if (behavior == CreateWarnAboutRequiredProperties) {
961 for (const auto &unsetRequiredProperty : std::as_const(t&: *state.requiredProperties())) {
962 const QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
963 qmlWarning(me: rv, error);
964 }
965 }
966 delete rv;
967 rv = nullptr;
968 }
969 return rv;
970}
971
972/*!
973 Create an object instance from this component, within the specified \a context.
974 Returns \nullptr if creation failed.
975
976 \note This method provides advanced control over component instance creation.
977 In general, programmers should use QQmlComponent::create() to create object
978 instances.
979
980 When QQmlComponent constructs an instance, it occurs in three steps:
981
982 \list 1
983 \li The object hierarchy is created, and constant values are assigned.
984 \li Property bindings are evaluated for the first time.
985 \li If applicable, QQmlParserStatus::componentComplete() is called on objects.
986 \endlist
987
988 QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
989 only performs step 1. QQmlComponent::completeCreate() must be called to
990 complete steps 2 and 3.
991
992 This breaking point is sometimes useful when using attached properties to
993 communicate information to an instantiated component, as it allows their
994 initial values to be configured before property bindings take effect.
995
996 The ownership of the returned object instance is transferred to the caller.
997
998 \sa completeCreate(), QQmlEngine::ObjectOwnership
999*/
1000QObject *QQmlComponent::beginCreate(QQmlContext *context)
1001{
1002 Q_D(QQmlComponent);
1003 Q_ASSERT(context);
1004 return d->beginCreate(QQmlContextData::get(context));
1005}
1006
1007QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> context)
1008{
1009 Q_Q(QQmlComponent);
1010 auto cleanup = qScopeGuard(f: [this] {
1011 if (!state.errors.isEmpty() && lcQmlComponentGeneral().isDebugEnabled()) {
1012 for (const auto &e : std::as_const(t&: state.errors)) {
1013 qCDebug(lcQmlComponentGeneral) << "QQmlComponent: " << e.error.toString();
1014 }
1015 }
1016 });
1017 if (!context) {
1018 qWarning(msg: "QQmlComponent: Cannot create a component in a null context");
1019 return nullptr;
1020 }
1021
1022 if (!context->isValid()) {
1023 qWarning(msg: "QQmlComponent: Cannot create a component in an invalid context");
1024 return nullptr;
1025 }
1026
1027 if (context->engine() != engine) {
1028 qWarning(msg: "QQmlComponent: Must create component in context from the same QQmlEngine");
1029 return nullptr;
1030 }
1031
1032 if (state.isCompletePending()) {
1033 qWarning(msg: "QQmlComponent: Cannot create new component instance before completing the previous");
1034 return nullptr;
1035 }
1036
1037 // filter out temporary errors as they do not really affect component's
1038 // state (they are not part of the document compilation)
1039 state.errors.erase(abegin: std::remove_if(first: state.errors.begin(), last: state.errors.end(),
1040 pred: [](const QQmlComponentPrivate::AnnotatedQmlError &e) {
1041 return e.isTransient;
1042 }),
1043 aend: state.errors.end());
1044 state.clearRequiredProperties();
1045
1046 if (!q->isReady()) {
1047 qWarning(msg: "QQmlComponent: Component is not ready");
1048 return nullptr;
1049 }
1050
1051 // Do not create infinite recursion in object creation
1052 static const int maxCreationDepth = 10;
1053 if (creationDepth >= maxCreationDepth) {
1054 qWarning(msg: "QQmlComponent: Component creation is recursing - aborting");
1055 return nullptr;
1056 }
1057
1058 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(e: engine);
1059
1060 enginePriv->inProgressCreations++;
1061 state.errors.clear();
1062 state.setCompletePending(true);
1063
1064 QObject *rv = nullptr;
1065
1066 if (!loadedType.isValid()) {
1067 enginePriv->referenceScarceResources();
1068 state.initCreator(parentContext: std::move(context), compilationUnit, creationContext);
1069
1070 QQmlObjectCreator::CreationFlags flags;
1071 if (const QString *icName = inlineComponentName.get()) {
1072 flags = QQmlObjectCreator::InlineComponent;
1073 if (start == -1)
1074 start = compilationUnit->inlineComponentId(inlineComponentName: *icName);
1075 Q_ASSERT(start > 0);
1076 } else {
1077 flags = QQmlObjectCreator::NormalObject;
1078 }
1079
1080 rv = state.creator()->create(subComponentIndex: start, parent: nullptr, interrupt: nullptr, flags);
1081 if (!rv)
1082 state.appendCreatorErrors();
1083 enginePriv->dereferenceScarceResources();
1084 } else {
1085 rv = loadedType.createWithQQmlData();
1086 QQmlPropertyCache::ConstPtr propertyCache = QQmlData::ensurePropertyCache(object: rv);
1087 for (int i = 0, propertyCount = propertyCache->propertyCount(); i < propertyCount; ++i) {
1088 if (const QQmlPropertyData *propertyData = propertyCache->property(index: i); propertyData->isRequired()) {
1089 state.ensureRequiredPropertyStorage();
1090 RequiredPropertyInfo info;
1091 info.propertyName = propertyData->name(rv);
1092 state.addPendingRequiredProperty(object: rv, propData: propertyData, info);
1093 }
1094 }
1095 }
1096
1097 if (rv) {
1098 QQmlData *ddata = QQmlData::get(object: rv);
1099 Q_ASSERT(ddata);
1100 // top-level objects should never get JS ownership.
1101 // if JS ownership is needed this needs to be explicitly undone (like in createObject())
1102 ddata->indestructible = true;
1103 ddata->explicitIndestructibleSet = true;
1104 ddata->rootObjectInCreation = false;
1105 }
1106
1107 return rv;
1108}
1109
1110void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
1111 QObject *object, DeferredState *deferredState)
1112{
1113 QQmlData *ddata = QQmlData::get(object);
1114 Q_ASSERT(!ddata->deferredData.isEmpty());
1115
1116 deferredState->reserve(n: ddata->deferredData.size());
1117
1118 for (QQmlData::DeferredData *deferredData : std::as_const(t&: ddata->deferredData)) {
1119 enginePriv->inProgressCreations++;
1120
1121 ConstructionState state;
1122 state.setCompletePending(true);
1123
1124 auto creator = state.initCreator(
1125 parentContext: deferredData->context->parent(),
1126 compilationUnit: deferredData->compilationUnit,
1127 creationContext: QQmlRefPointer<QQmlContextData>());
1128
1129 if (!creator->populateDeferredProperties(instance: object, deferredData))
1130 state.appendCreatorErrors();
1131 deferredData->bindings.clear();
1132
1133 deferredState->push_back(x: std::move(state));
1134 }
1135}
1136
1137void QQmlComponentPrivate::completeDeferred(QQmlEnginePrivate *enginePriv, QQmlComponentPrivate::DeferredState *deferredState)
1138{
1139 for (ConstructionState &state : *deferredState)
1140 complete(enginePriv, state: &state);
1141}
1142
1143void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state)
1144{
1145 if (state->isCompletePending()) {
1146 QQmlInstantiationInterrupt interrupt;
1147 state->creator()->finalize(interrupt);
1148
1149 state->setCompletePending(false);
1150
1151 enginePriv->inProgressCreations--;
1152
1153 if (0 == enginePriv->inProgressCreations) {
1154 while (enginePriv->erroredBindings) {
1155 enginePriv->warning(enginePriv->erroredBindings->removeError());
1156 }
1157 }
1158 }
1159}
1160
1161/*!
1162 \internal
1163 Finds the matching top-level property with name \a name of the component \a createdComponent.
1164 If it was a required property or an alias to a required property contained in \a
1165 requiredProperties, it is removed from it.
1166 \a requiredProperties must be non-null.
1167
1168 If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
1169 was found in requiredProperties.
1170
1171 Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
1172 for further processing (for instance, actually setting the property value).
1173
1174 Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
1175 classes which create components should not need it and should only need to call
1176 setInitialProperties.
1177 */
1178QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(
1179 QObject *createdComponent, const QString &name, RequiredProperties *requiredProperties,
1180 QQmlEngine *engine, bool *wasInRequiredProperties)
1181{
1182 Q_ASSERT(requiredProperties);
1183 QQmlProperty prop(createdComponent, name, engine);
1184 auto privProp = QQmlPropertyPrivate::get(p: prop);
1185 if (prop.isValid()) {
1186 // resolve outstanding required properties
1187 const QQmlPropertyData *targetProp = &privProp->core;
1188 if (targetProp->isAlias()) {
1189 auto target = createdComponent;
1190 QQmlPropertyIndex originalIndex(targetProp->coreIndex());
1191 QQmlPropertyIndex propIndex;
1192 QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
1193 QQmlData *data = QQmlData::get(object: target);
1194 Q_ASSERT(data && data->propertyCache);
1195 targetProp = data->propertyCache->property(index: propIndex.coreIndex());
1196 } else {
1197 // we need to get the pointer from the property cache instead of directly using
1198 // targetProp else the lookup will fail
1199 QQmlData *data = QQmlData::get(object: createdComponent);
1200 Q_ASSERT(data && data->propertyCache);
1201 targetProp = data->propertyCache->property(index: targetProp->coreIndex());
1202 }
1203 auto it = requiredProperties->find(key: {createdComponent, targetProp});
1204 if (it != requiredProperties->end()) {
1205 if (wasInRequiredProperties)
1206 *wasInRequiredProperties = true;
1207 requiredProperties->erase(it);
1208 } else {
1209 if (wasInRequiredProperties)
1210 *wasInRequiredProperties = false;
1211 }
1212 }
1213 return prop;
1214}
1215
1216/*!
1217 This method provides advanced control over component instance creation.
1218 In general, programmers should use QQmlComponent::create() to create a
1219 component.
1220
1221 This function completes the component creation begun with QQmlComponent::beginCreate()
1222 and must be called afterwards.
1223
1224 \sa beginCreate()
1225*/
1226void QQmlComponent::completeCreate()
1227{
1228 Q_D(QQmlComponent);
1229
1230 d->completeCreate();
1231}
1232
1233void QQmlComponentPrivate::completeCreate()
1234{
1235 if (state.hasUnsetRequiredProperties()) {
1236 for (const auto& unsetRequiredProperty: std::as_const(t&: *state.requiredProperties())) {
1237 QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
1238 state.errors.push_back(t: QQmlComponentPrivate::AnnotatedQmlError { error, true });
1239 }
1240 }
1241 if (loadedType.isValid()) {
1242 /*
1243 We can directly set completePending to false, as finalize is only concerned
1244 with setting up pending bindings, but that cannot happen here, as we're
1245 dealing with a pure C++ type, which cannot have pending bindings
1246 */
1247 state.setCompletePending(false);
1248 QQmlEnginePrivate::get(e: engine)->inProgressCreations--;
1249 } else if (state.isCompletePending()) {
1250 ++creationDepth;
1251 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(e: engine);
1252 complete(enginePriv: ep, state: &state);
1253 --creationDepth;
1254 }
1255}
1256
1257QQmlComponentAttached::QQmlComponentAttached(QObject *parent)
1258: QObject(parent), m_prev(nullptr), m_next(nullptr)
1259{
1260}
1261
1262QQmlComponentAttached::~QQmlComponentAttached()
1263{
1264 if (m_prev) *m_prev = m_next;
1265 if (m_next) m_next->m_prev = m_prev;
1266 m_prev = nullptr;
1267 m_next = nullptr;
1268}
1269
1270/*!
1271 \internal
1272*/
1273QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
1274{
1275 QQmlComponentAttached *a = new QQmlComponentAttached(obj);
1276
1277 QQmlEngine *engine = qmlEngine(obj);
1278 if (!engine)
1279 return a;
1280
1281 QQmlEnginePrivate *p = QQmlEnginePrivate::get(e: engine);
1282 if (p->activeObjectCreator) { // XXX should only be allowed during begin
1283 a->insertIntoList(listHead: p->activeObjectCreator->componentAttachment());
1284 } else {
1285 QQmlData *d = QQmlData::get(object: obj);
1286 Q_ASSERT(d);
1287 Q_ASSERT(d->context);
1288 d->context->addComponentAttached(attached: a);
1289 }
1290
1291 return a;
1292}
1293
1294/*!
1295 Load the QQmlComponent for \a typeName in the module \a uri.
1296 If the type is implemented via a QML file, \a mode is used to
1297 load it. Types backed by C++ are always loaded synchronously.
1298
1299 \code
1300 QQmlEngine engine;
1301 QQmlComponent component(&engine);
1302 component.loadFromModule("QtQuick", "Item");
1303 // once the component is ready
1304 std::unique_ptr<QObject> item(component.create());
1305 Q_ASSERT(item->metaObject() == &QQuickItem::staticMetaObject);
1306 \endcode
1307
1308 \since 6.5
1309 \sa loadUrl()
1310 */
1311void QQmlComponent::loadFromModule(QAnyStringView uri, QAnyStringView typeName,
1312 QQmlComponent::CompilationMode mode)
1313{
1314 Q_D(QQmlComponent);
1315
1316 auto enginePriv = QQmlEnginePrivate::get(e: d->engine);
1317 // LoadHelper must be on the Heap as it derives from QQmlRefCount
1318 auto loadHelper = QQml::makeRefPointer<LoadHelper>(args: &enginePriv->typeLoader, args&: uri);
1319
1320 auto [moduleStatus, type] = loadHelper->resolveType(typeName);
1321 auto reportError = [&](QString msg) {
1322 QQmlError error;
1323 error.setDescription(msg);
1324 d->state.errors.push_back(t: std::move(error));
1325 emit statusChanged(Error);
1326 };
1327 if (moduleStatus == LoadHelper::ResolveTypeResult::NoSuchModule) {
1328 reportError(QLatin1String(R"(No module named "%1" found)")
1329 .arg(args: uri.toString()));
1330 } else if (!type.isValid()) {
1331 reportError(QLatin1String(R"(Module "%1" contains no type named "%2")")
1332 .arg(args: uri.toString(), args: typeName.toString()));
1333 } else if (type.isCreatable()) {
1334 d->clear();
1335 // mimic the progressChanged behavior from loadUrl
1336 if (d->progress != 0) {
1337 d->progress = 0;
1338 emit progressChanged(0);
1339 }
1340 d->loadedType = type;
1341 d->progress = 1;
1342 emit progressChanged(1);
1343 emit statusChanged(status());
1344
1345 } else if (type.isComposite()) {
1346 loadUrl(url: type.sourceUrl(), mode);
1347 } else if (type.isInlineComponentType()) {
1348 auto baseUrl = type.sourceUrl();
1349 baseUrl.setFragment(fragment: QString());
1350 loadUrl(url: baseUrl, mode);
1351 if (!isError()) {
1352 d->inlineComponentName = std::make_unique<QString>(args: type.elementName());
1353 Q_ASSERT(!d->inlineComponentName->isEmpty());
1354 }
1355 } else if (type.isSingleton() || type.isCompositeSingleton()) {
1356 reportError(QLatin1String(R"(%1 is a singleton, and cannot be loaded)")
1357 .arg(args: typeName.toString()));
1358 } else {
1359 reportError(QLatin1String("Could not load %1, as the type is uncreatable")
1360 .arg(args: typeName.toString()));
1361 }
1362}
1363
1364/*!
1365 Create an object instance from this component using the provided
1366 \a incubator. \a context specifies the context within which to create the object
1367 instance.
1368
1369 If \a context is \nullptr (by default), it will create the instance in the
1370 engine's \l {QQmlEngine::rootContext()}{root context}.
1371
1372 \a forContext specifies a context that this object creation depends upon.
1373 If the \a forContext is being created asynchronously, and the
1374 \l QQmlIncubator::IncubationMode is \l QQmlIncubator::AsynchronousIfNested,
1375 this object will also be created asynchronously.
1376 If \a forContext is \nullptr (by default), the \a context will be used for this decision.
1377
1378 The created object and its creation status are available via the
1379 \a incubator.
1380
1381 \sa QQmlIncubator
1382*/
1383
1384void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlContext *forContext)
1385{
1386 Q_D(QQmlComponent);
1387
1388 if (!context)
1389 context = d->engine->rootContext();
1390
1391 QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
1392 QQmlRefPointer<QQmlContextData> forContextData =
1393 forContext ? QQmlContextData::get(context: forContext) : contextData;
1394
1395 if (!contextData->isValid()) {
1396 qWarning(msg: "QQmlComponent: Cannot create a component in an invalid context");
1397 return;
1398 }
1399
1400 if (contextData->engine() != d->engine) {
1401 qWarning(msg: "QQmlComponent: Must create component in context from the same QQmlEngine");
1402 return;
1403 }
1404
1405 if (!isReady()) {
1406 qWarning(msg: "QQmlComponent: Component is not ready");
1407 return;
1408 }
1409
1410 incubator.clear();
1411 QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(incubator.d);
1412
1413 if (d->loadedType.isValid()) {
1414 // there isn't really an incubation process for C++ backed types
1415 // so just create the object and signal that we are ready
1416
1417 p->incubateCppBasedComponent(component: this, context);
1418 return;
1419 }
1420
1421 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(e: d->engine);
1422
1423 p->compilationUnit = d->compilationUnit;
1424 p->enginePriv = enginePriv;
1425 p->creator.reset(other: new QQmlObjectCreator(contextData, d->compilationUnit, d->creationContext, p.data()));
1426 p->subComponentToCreate = d->start;
1427
1428 enginePriv->incubate(incubator, forContextData);
1429}
1430
1431/*!
1432 Set top-level \a properties of the \a component.
1433
1434 This method provides advanced control over component instance creation.
1435 In general, programmers should use
1436 \l QQmlComponent::createWithInitialProperties to create a component.
1437
1438 Use this method after beginCreate and before completeCreate has been called.
1439 If a provided property does not exist, a warning is issued.
1440
1441 \since 5.14
1442*/
1443void QQmlComponent::setInitialProperties(QObject *component, const QVariantMap &properties)
1444{
1445 Q_D(QQmlComponent);
1446 for (auto it = properties.constBegin(); it != properties.constEnd(); ++it)
1447 d->setInitialProperty(base: component, name: it.key(), value: it.value());
1448}
1449
1450/*
1451 This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
1452 arguments instead of QQmlContext which means we don't have to construct the rather weighty
1453 wrapper class for every delegate item.
1454
1455 This is used by QQmlDelegateModel.
1456*/
1457void QQmlComponentPrivate::incubateObject(
1458 QQmlIncubator *incubationTask,
1459 QQmlComponent *component,
1460 QQmlEngine *engine,
1461 const QQmlRefPointer<QQmlContextData> &context,
1462 const QQmlRefPointer<QQmlContextData> &forContext)
1463{
1464 QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubator: incubationTask);
1465 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(e: engine);
1466 QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(c: component);
1467
1468 incubatorPriv->compilationUnit = componentPriv->compilationUnit;
1469 incubatorPriv->enginePriv = enginePriv;
1470 incubatorPriv->creator.reset(other: new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
1471
1472 if (start == -1) {
1473 if (const QString *icName = componentPriv->inlineComponentName.get()) {
1474 start = compilationUnit->inlineComponentId(inlineComponentName: *icName);
1475 Q_ASSERT(start > 0);
1476 }
1477 }
1478 incubatorPriv->subComponentToCreate = componentPriv->start;
1479
1480 enginePriv->incubate(*incubationTask, forContext);
1481}
1482
1483
1484
1485class QQmlComponentIncubator;
1486
1487namespace QV4 {
1488
1489namespace Heap {
1490
1491#define QmlIncubatorObjectMembers(class, Member) \
1492 Member(class, HeapValue, HeapValue, valuemap) \
1493 Member(class, HeapValue, HeapValue, statusChanged) \
1494 Member(class, Pointer, QmlContext *, qmlContext) \
1495 Member(class, NoMark, QQmlComponentIncubator *, incubator) \
1496 Member(class, NoMark, QV4QPointer<QObject>, parent)
1497
1498DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) {
1499 DECLARE_MARKOBJECTS(QmlIncubatorObject)
1500
1501 void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
1502 inline void destroy();
1503};
1504
1505}
1506
1507struct QmlIncubatorObject : public QV4::Object
1508{
1509 V4_OBJECT2(QmlIncubatorObject, Object)
1510 V4_NEEDS_DESTROY
1511
1512 static ReturnedValue method_get_statusChanged(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
1513 static ReturnedValue method_set_statusChanged(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
1514 static ReturnedValue method_get_status(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
1515 static ReturnedValue method_get_object(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
1516 static ReturnedValue method_forceCompletion(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
1517
1518 void statusChanged(QQmlIncubator::Status);
1519 void setInitialState(QObject *, RequiredProperties *requiredProperties);
1520};
1521
1522}
1523
1524DEFINE_OBJECT_VTABLE(QV4::QmlIncubatorObject);
1525
1526class QQmlComponentIncubator : public QQmlIncubator
1527{
1528public:
1529 QQmlComponentIncubator(QV4::Heap::QmlIncubatorObject *inc, IncubationMode mode)
1530 : QQmlIncubator(mode)
1531 {
1532 incubatorObject.set(engine: inc->internalClass->engine, obj: inc);
1533 }
1534
1535 void statusChanged(Status s) override {
1536 QV4::Scope scope(incubatorObject.engine());
1537 QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject.as<QV4::QmlIncubatorObject>());
1538 i->statusChanged(s);
1539 }
1540
1541 void setInitialState(QObject *o) override {
1542 QV4::Scope scope(incubatorObject.engine());
1543 QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject.as<QV4::QmlIncubatorObject>());
1544 auto d = QQmlIncubatorPrivate::get(incubator: this);
1545 i->setInitialState(o, requiredProperties: d->requiredProperties());
1546 }
1547
1548 QV4::PersistentValue incubatorObject; // keep a strong internal reference while incubating
1549};
1550
1551
1552static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
1553{
1554 if (parent) {
1555 me->setParent(parent);
1556 typedef QQmlPrivate::AutoParentFunction APF;
1557 QList<APF> functions = QQmlMetaType::parentFunctions();
1558
1559 bool needParent = false;
1560 for (int ii = 0; ii < functions.size(); ++ii) {
1561 QQmlPrivate::AutoParentResult res = functions.at(i: ii)(me, parent);
1562 if (res == QQmlPrivate::Parented) {
1563 needParent = false;
1564 break;
1565 } else if (res == QQmlPrivate::IncompatibleParent) {
1566 needParent = true;
1567 }
1568 }
1569 if (needParent)
1570 qmlWarning(me) << "Created graphical object was not placed in the graphics scene.";
1571 }
1572}
1573
1574/*!
1575 \qmlmethod QtObject Component::createObject(QtObject parent, object properties)
1576
1577 Creates and returns an object instance of this component that will have
1578 the given \a parent and \a properties. The \a properties argument is optional.
1579 Returns null if object creation fails.
1580
1581 The object will be created in the same context as the one in which the component
1582 was created. This function will always return null when called on components
1583 which were not created in QML.
1584
1585 If you wish to create an object without setting a parent, specify \c null for
1586 the \a parent value. Note that if the returned object is to be displayed, you
1587 must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
1588 property, otherwise the object will not be visible.
1589
1590 If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
1591 it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
1592 because setting the Item parent does not change object ownership. Only the graphical parent is changed.
1593
1594 As of \c {QtQuick 1.1}, this method accepts an optional \a properties argument that specifies a
1595 map of initial property values for the created object. These values are applied before the object
1596 creation is finalized. This is more efficient than setting property values after object creation,
1597 particularly where large sets of property values are defined, and also allows property bindings
1598 to be set up (using \l{Qt::binding}{Qt.binding}) before the object is created.
1599
1600 The \a properties argument is specified as a map of property-value items. For example, the code
1601 below creates an object with initial \c x and \c y values of 100 and 100, respectively:
1602
1603 \qml
1604 const component = Qt.createComponent("Button.qml");
1605 if (component.status === Component.Ready) {
1606 component.createObject(parent, { x: 100, y: 100 });
1607 }
1608 \endqml
1609
1610 Dynamically created instances can be deleted with the \c destroy() method.
1611 See \l {Dynamic QML Object Creation from JavaScript} for more information.
1612
1613 \sa incubateObject()
1614*/
1615
1616
1617void QQmlComponentPrivate::setInitialProperties(
1618 QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o,
1619 const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent,
1620 QQmlObjectCreator *creator)
1621{
1622 QV4::Scope scope(engine);
1623 QV4::ScopedObject object(scope);
1624 QV4::ScopedObject valueMap(scope, v);
1625 QV4::ObjectIterator it(scope, valueMap, QV4::ObjectIterator::EnumerableOnly);
1626 QV4::ScopedString name(scope);
1627 QV4::ScopedValue val(scope);
1628 if (engine->hasException)
1629 return;
1630
1631 // js modules (mjs) have no qmlContext
1632 QV4::ScopedStackFrame frame(scope, qmlContext ? qmlContext : engine->scriptContext());
1633
1634 while (1) {
1635 name = it.nextPropertyNameAsString(value: val);
1636 if (!name)
1637 break;
1638 object = o;
1639 const QStringList properties = name->toQString().split(sep: QLatin1Char('.'));
1640 bool isTopLevelProperty = properties.size() == 1;
1641 for (int i = 0; i < properties.size() - 1; ++i) {
1642 name = engine->newString(s: properties.at(i));
1643 object = object->get(name);
1644 if (engine->hasException || !object) {
1645 break;
1646 }
1647 }
1648 if (engine->hasException) {
1649 qmlWarning(me: createdComponent, error: engine->catchExceptionAsQmlError());
1650 continue;
1651 }
1652 if (!object) {
1653 QQmlError error;
1654 error.setUrl(qmlContext ? qmlContext->qmlContext()->url() : QUrl());
1655 error.setDescription(QLatin1String("Cannot resolve property \"%1\".")
1656 .arg(args: properties.join(sep: u'.')));
1657 qmlWarning(me: createdComponent, error);
1658 continue;
1659 }
1660 const QString lastProperty = properties.last();
1661 name = engine->newString(s: lastProperty);
1662 object->put(name, v: val);
1663 if (engine->hasException) {
1664 qmlWarning(me: createdComponent, error: engine->catchExceptionAsQmlError());
1665 continue;
1666 } else if (isTopLevelProperty && requiredProperties) {
1667 auto prop = removePropertyFromRequired(createdComponent, name: name->toQString(),
1668 requiredProperties, engine: engine->qmlEngine());
1669 }
1670
1671 removePendingQPropertyBinding(object, propertyName: lastProperty, creator);
1672 }
1673
1674 engine->hasException = false;
1675}
1676
1677QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty)
1678{
1679 QQmlError error;
1680 QString description = QLatin1String("Required property %1 was not initialized").arg(args: unsetRequiredProperty.propertyName);
1681 switch (unsetRequiredProperty.aliasesToRequired.size()) {
1682 case 0:
1683 break;
1684 case 1: {
1685 const auto info = unsetRequiredProperty.aliasesToRequired.first();
1686 description += QLatin1String("\nIt can be set via the alias property %1 from %2\n").arg(args: info.propertyName, args: info.fileUrl.toString());
1687 break;
1688 }
1689 default:
1690 description += QLatin1String("\nIt can be set via one of the following alias properties:");
1691 for (auto aliasInfo: unsetRequiredProperty.aliasesToRequired) {
1692 description += QLatin1String("\n- %1 (%2)").arg(args&: aliasInfo.propertyName, args: aliasInfo.fileUrl.toString());
1693 }
1694 description += QLatin1Char('\n');
1695 }
1696 error.setDescription(description);
1697 error.setUrl(unsetRequiredProperty.fileUrl);
1698 error.setLine(qmlConvertSourceCoordinate<quint32, int>(
1699 n: unsetRequiredProperty.location.line()));
1700 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
1701 n: unsetRequiredProperty.location.column()));
1702 return error;
1703}
1704
1705#if QT_DEPRECATED_SINCE(6, 3)
1706/*!
1707 \internal
1708*/
1709void QQmlComponent::createObject(QQmlV4Function *args)
1710{
1711 Q_D(QQmlComponent);
1712 Q_ASSERT(d->engine);
1713 Q_ASSERT(args);
1714
1715 qmlWarning(me: this) << "Unsuitable arguments passed to createObject(). The first argument should "
1716 "be a QObject* or null, and the second argument should be a JavaScript "
1717 "object or a QVariantMap";
1718
1719 QObject *parent = nullptr;
1720 QV4::ExecutionEngine *v4 = args->v4engine();
1721 QV4::Scope scope(v4);
1722 QV4::ScopedValue valuemap(scope, QV4::Value::undefinedValue());
1723
1724 if (args->length() >= 1) {
1725 QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, (*args)[0]);
1726 if (qobjectWrapper)
1727 parent = qobjectWrapper->object();
1728 }
1729
1730 if (args->length() >= 2) {
1731 QV4::ScopedValue v(scope, (*args)[1]);
1732 if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) {
1733 qmlWarning(me: this) << tr(s: "createObject: value is not an object");
1734 args->setReturnValue(QV4::Encode::null());
1735 return;
1736 }
1737 valuemap = v;
1738 }
1739
1740 QQmlContext *ctxt = creationContext();
1741 if (!ctxt) ctxt = d->engine->rootContext();
1742
1743 QObject *rv = beginCreate(context: ctxt);
1744
1745 if (!rv) {
1746 args->setReturnValue(QV4::Encode::null());
1747 return;
1748 }
1749
1750 QQmlComponent_setQmlParent(me: rv, parent);
1751
1752 QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine: v4, object: rv));
1753 Q_ASSERT(object->isObject());
1754
1755 if (!valuemap->isUndefined()) {
1756 QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext());
1757 QQmlComponentPrivate::setInitialProperties(
1758 engine: v4, qmlContext, o: object, v: valuemap, requiredProperties: d->state.requiredProperties(), createdComponent: rv,
1759 creator: d->state.creator());
1760 }
1761 if (d->state.hasUnsetRequiredProperties()) {
1762 QList<QQmlError> errors;
1763 for (const auto &requiredProperty: std::as_const(t&: *d->state.requiredProperties())) {
1764 errors.push_back(t: QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(unsetRequiredProperty: requiredProperty));
1765 }
1766 qmlWarning(me: rv, errors);
1767 args->setReturnValue(QV4::Encode::null());
1768 delete rv;
1769 return;
1770 }
1771
1772 d->completeCreate();
1773
1774 Q_ASSERT(QQmlData::get(rv));
1775 QQmlData::get(object: rv)->explicitIndestructibleSet = false;
1776 QQmlData::get(object: rv)->indestructible = false;
1777
1778 args->setReturnValue(object->asReturnedValue());
1779}
1780#endif
1781
1782/*!
1783 \internal
1784 */
1785QObject *QQmlComponent::createObject(QObject *parent, const QVariantMap &properties)
1786{
1787 Q_D(QQmlComponent);
1788 Q_ASSERT(d->engine);
1789 QObject *rv = d->createWithProperties(parent, properties, context: creationContext(),
1790 behavior: QQmlComponentPrivate::CreateWarnAboutRequiredProperties);
1791 if (rv) {
1792 QQmlData *qmlData = QQmlData::get(object: rv);
1793 Q_ASSERT(qmlData);
1794 qmlData->explicitIndestructibleSet = false;
1795 qmlData->indestructible = false;
1796 }
1797 return rv;
1798}
1799
1800/*!
1801 \qmlmethod object Component::incubateObject(QtObject parent, object properties, enumeration mode)
1802
1803 Creates an incubator for an instance of this component. Incubators allow new component
1804 instances to be instantiated asynchronously and do not cause freezes in the UI.
1805
1806 The \a parent argument specifies the parent the created instance will have. Omitting the
1807 parameter or passing null will create an object with no parent. In this case, a reference
1808 to the created object must be held so that it is not destroyed by the garbage collector.
1809
1810 The \a properties argument is specified as a map of property-value items which will be
1811 set on the created object during its construction. \a mode may be Qt.Synchronous or
1812 Qt.Asynchronous, and controls whether the instance is created synchronously or asynchronously.
1813 The default is asynchronous. In some circumstances, even if Qt.Synchronous is specified,
1814 the incubator may create the object asynchronously. This happens if the component calling
1815 incubateObject() is itself being created asynchronously.
1816
1817 All three arguments are optional.
1818
1819 If successful, the method returns an incubator, otherwise null. The incubator has the following
1820 properties:
1821
1822 \list
1823 \li \c status - The status of the incubator. Valid values are Component.Ready, Component.Loading and
1824 Component.Error.
1825 \li \c object - The created object instance. Will only be available once the incubator is in the
1826 Ready status.
1827 \li \c onStatusChanged - Specifies a callback function to be invoked when the status changes. The
1828 status is passed as a parameter to the callback.
1829 \li \c{forceCompletion()} - Call to complete incubation synchronously.
1830 \endlist
1831
1832 The following example demonstrates how to use an incubator:
1833
1834 \qml
1835 const component = Qt.createComponent("Button.qml");
1836
1837 const incubator = component.incubateObject(parent, { x: 10, y: 10 });
1838 if (incubator.status !== Component.Ready) {
1839 incubator.onStatusChanged = function(status) {
1840 if (status === Component.Ready) {
1841 print("Object", incubator.object, "is now ready!");
1842 }
1843 };
1844 } else {
1845 print("Object", incubator.object, "is ready immediately!");
1846 }
1847 \endqml
1848
1849 Dynamically created instances can be deleted with the \c destroy() method.
1850 See \l {Dynamic QML Object Creation from JavaScript} for more information.
1851
1852 \sa createObject()
1853*/
1854
1855/*!
1856 \internal
1857*/
1858void QQmlComponent::incubateObject(QQmlV4Function *args)
1859{
1860 Q_D(QQmlComponent);
1861 Q_ASSERT(d->engine);
1862 Q_UNUSED(d);
1863 Q_ASSERT(args);
1864 QV4::ExecutionEngine *v4 = args->v4engine();
1865 QV4::Scope scope(v4);
1866
1867 QObject *parent = nullptr;
1868 QV4::ScopedValue valuemap(scope, QV4::Value::undefinedValue());
1869 QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous;
1870
1871 if (args->length() >= 1) {
1872 QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, (*args)[0]);
1873 if (qobjectWrapper)
1874 parent = qobjectWrapper->object();
1875 }
1876
1877 if (args->length() >= 2) {
1878 QV4::ScopedValue v(scope, (*args)[1]);
1879 if (v->isNull()) {
1880 } else if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) {
1881 qmlWarning(me: this) << tr(s: "createObject: value is not an object");
1882 args->setReturnValue(QV4::Encode::null());
1883 return;
1884 } else {
1885 valuemap = v;
1886 }
1887 }
1888
1889 if (args->length() >= 3) {
1890 QV4::ScopedValue val(scope, (*args)[2]);
1891 quint32 v = val->toUInt32();
1892 if (v == 0)
1893 mode = QQmlIncubator::Asynchronous;
1894 else if (v == 1)
1895 mode = QQmlIncubator::AsynchronousIfNested;
1896 }
1897
1898 QQmlComponentExtension *e = componentExtension(engine: args->v4engine());
1899
1900 QV4::Scoped<QV4::QmlIncubatorObject> r(scope, v4->memoryManager->allocate<QV4::QmlIncubatorObject>(args&: mode));
1901 QV4::ScopedObject p(scope, e->incubationProto.value());
1902 r->setPrototypeOf(p);
1903
1904 if (!valuemap->isUndefined())
1905 r->d()->valuemap.set(e: scope.engine, newVal: valuemap);
1906 r->d()->qmlContext.set(e: scope.engine, newVal: v4->qmlContext());
1907 r->d()->parent = parent;
1908
1909 QQmlIncubator *incubator = r->d()->incubator;
1910 create(incubator&: *incubator, context: creationContext());
1911
1912 if (incubator->status() == QQmlIncubator::Null) {
1913 args->setReturnValue(QV4::Encode::null());
1914 } else {
1915 args->setReturnValue(r.asReturnedValue());
1916 }
1917}
1918
1919// XXX used by QSGLoader
1920void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties *requiredProperties)
1921{
1922 QV4::ExecutionEngine *v4engine = engine->handle();
1923 QV4::Scope scope(v4engine);
1924
1925 QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine: v4engine, object: toCreate));
1926 Q_ASSERT(object->as<QV4::Object>());
1927
1928 if (!valuemap.isUndefined()) {
1929 setInitialProperties(
1930 engine: v4engine, qmlContext, o: object, v: valuemap, requiredProperties, createdComponent: toCreate, creator: state.creator());
1931 }
1932}
1933
1934QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4)
1935{
1936 QV4::Scope scope(v4);
1937 QV4::ScopedObject proto(scope, v4->newObject());
1938 proto->defineAccessorProperty(QStringLiteral("onStatusChanged"),
1939 getter: QV4::QmlIncubatorObject::method_get_statusChanged, setter: QV4::QmlIncubatorObject::method_set_statusChanged);
1940 proto->defineAccessorProperty(QStringLiteral("status"), getter: QV4::QmlIncubatorObject::method_get_status, setter: nullptr);
1941 proto->defineAccessorProperty(QStringLiteral("object"), getter: QV4::QmlIncubatorObject::method_get_object, setter: nullptr);
1942 proto->defineDefaultProperty(QStringLiteral("forceCompletion"), code: QV4::QmlIncubatorObject::method_forceCompletion);
1943
1944 incubationProto.set(engine: v4, value: proto);
1945}
1946
1947QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_object(const FunctionObject *b, const Value *thisObject, const Value *, int)
1948{
1949 QV4::Scope scope(b);
1950 QV4::Scoped<QmlIncubatorObject> o(scope, thisObject->as<QmlIncubatorObject>());
1951 if (!o)
1952 THROW_TYPE_ERROR();
1953
1954 return QV4::QObjectWrapper::wrap(engine: scope.engine, object: o->d()->incubator->object());
1955}
1956
1957QV4::ReturnedValue QV4::QmlIncubatorObject::method_forceCompletion(const FunctionObject *b, const Value *thisObject, const Value *, int)
1958{
1959 QV4::Scope scope(b);
1960 QV4::Scoped<QmlIncubatorObject> o(scope, thisObject->as<QmlIncubatorObject>());
1961 if (!o)
1962 THROW_TYPE_ERROR();
1963
1964 o->d()->incubator->forceCompletion();
1965
1966 RETURN_UNDEFINED();
1967}
1968
1969QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_status(const FunctionObject *b, const Value *thisObject, const Value *, int)
1970{
1971 QV4::Scope scope(b);
1972 QV4::Scoped<QmlIncubatorObject> o(scope, thisObject->as<QmlIncubatorObject>());
1973 if (!o)
1974 THROW_TYPE_ERROR();
1975
1976 return QV4::Encode(o->d()->incubator->status());
1977}
1978
1979QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_statusChanged(const FunctionObject *b, const Value *thisObject, const Value *, int)
1980{
1981 QV4::Scope scope(b);
1982 QV4::Scoped<QmlIncubatorObject> o(scope, thisObject->as<QmlIncubatorObject>());
1983 if (!o)
1984 THROW_TYPE_ERROR();
1985
1986 return QV4::Encode(o->d()->statusChanged);
1987}
1988
1989QV4::ReturnedValue QV4::QmlIncubatorObject::method_set_statusChanged(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1990{
1991 QV4::Scope scope(b);
1992 QV4::Scoped<QmlIncubatorObject> o(scope, thisObject->as<QmlIncubatorObject>());
1993 if (!o || argc < 1)
1994 THROW_TYPE_ERROR();
1995
1996 o->d()->statusChanged.set(e: scope.engine, newVal: argv[0]);
1997
1998 RETURN_UNDEFINED();
1999}
2000
2001QQmlComponentExtension::~QQmlComponentExtension()
2002{
2003}
2004
2005void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m)
2006{
2007 Object::init();
2008 valuemap.set(e: internalClass->engine, newVal: QV4::Value::undefinedValue());
2009 statusChanged.set(e: internalClass->engine, newVal: QV4::Value::undefinedValue());
2010 parent.init();
2011 qmlContext.set(e: internalClass->engine, newVal: nullptr);
2012 incubator = new QQmlComponentIncubator(this, m);
2013}
2014
2015void QV4::Heap::QmlIncubatorObject::destroy() {
2016 delete incubator;
2017 parent.destroy();
2018 Object::destroy();
2019}
2020
2021void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties *requiredProperties)
2022{
2023 QQmlComponent_setQmlParent(me: o, parent: d()->parent);
2024
2025 if (!d()->valuemap.isUndefined()) {
2026 QV4::ExecutionEngine *v4 = engine();
2027 QV4::Scope scope(v4);
2028 QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(engine: v4, object: o));
2029 QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext);
2030 QQmlComponentPrivate::setInitialProperties(
2031 engine: v4, qmlContext: qmlCtxt, o: obj, v: d()->valuemap, requiredProperties, createdComponent: o,
2032 creator: QQmlIncubatorPrivate::get(incubator: d()->incubator)->creator.data());
2033 }
2034}
2035
2036void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
2037{
2038 QV4::Scope scope(engine());
2039 // hold the incubated object in a scoped value to prevent it's destruction before this method returns
2040 QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(engine: scope.engine, object: d()->incubator->object()));
2041
2042 if (s == QQmlIncubator::Ready) {
2043 Q_ASSERT(QQmlData::get(d()->incubator->object()));
2044 QQmlData::get(object: d()->incubator->object())->explicitIndestructibleSet = false;
2045 QQmlData::get(object: d()->incubator->object())->indestructible = false;
2046 }
2047
2048 QV4::ScopedFunctionObject f(scope, d()->statusChanged);
2049 if (f) {
2050 QV4::JSCallArguments jsCallData(scope, 1);
2051 *jsCallData.thisObject = this;
2052 jsCallData.args[0] = QV4::Value::fromUInt32(i: s);
2053 f->call(data: jsCallData);
2054 if (scope.hasException()) {
2055 QQmlError error = scope.engine->catchExceptionAsQmlError();
2056 QQmlEnginePrivate::warning(QQmlEnginePrivate::get(e: scope.engine->qmlEngine()), error);
2057 }
2058 }
2059
2060 if (s != QQmlIncubator::Loading)
2061 d()->incubator->incubatorObject.clear();
2062}
2063
2064#undef INITIALPROPERTIES_SOURCE
2065
2066QT_END_NAMESPACE
2067
2068#include "moc_qqmlcomponent.cpp"
2069#include "moc_qqmlcomponentattached_p.cpp"
2070

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