QQmlComponent/QQmlIncubator: Support C++ based types
QQmlComponent has a create overload which takes an Incubator. While there is not really any work that could be done in an asynchronous with a C++ based types (there are no sub-QML components, and there are no bindings to set up), we still have to accommodate them in that overload (otherwise we'd crash due to the missing compilation unit). Add support in QQmlIncubator for this case, and call the newly introduce function in QQmlComponent::create. Task-number: QTBUG-97156 Change-Id: I64e3c6958117920dca214eee633424de94b492db Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
e2fcd32004
commit
9b3813be28
|
@ -1406,6 +1406,14 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlC
|
|||
incubator.clear();
|
||||
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(incubator.d);
|
||||
|
||||
if (d->loadedType.isValid()) {
|
||||
// there isn't really an incubation process for C++ backed types
|
||||
// so just create the object and signal that we are ready
|
||||
|
||||
p->incubateCppBasedComponent(this, context);
|
||||
return;
|
||||
}
|
||||
|
||||
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
|
||||
|
||||
p->compilationUnit = d->compilationUnit;
|
||||
|
|
|
@ -103,6 +103,9 @@ QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
|
|||
|
||||
void QQmlIncubatorPrivate::clear()
|
||||
{
|
||||
// reset the tagged pointer
|
||||
if (requiredPropertiesFromComponent)
|
||||
requiredPropertiesFromComponent = decltype(requiredPropertiesFromComponent){};
|
||||
compilationUnit.reset();
|
||||
if (next.isInList()) {
|
||||
next.remove();
|
||||
|
@ -373,6 +376,35 @@ finishIncubate:
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
This is used to mimic the behavior of incubate when the
|
||||
Component we want to incubate refers to a creatable
|
||||
QQmlType (i.e., it is the result of loadFromModule).
|
||||
*/
|
||||
void QQmlIncubatorPrivate::incubateCppBasedComponent(QQmlComponent *component, QQmlContext *context)
|
||||
{
|
||||
auto compPriv = QQmlComponentPrivate::get(component);
|
||||
Q_ASSERT(compPriv->loadedType.isCreatable());
|
||||
std::unique_ptr<QObject> object(component->beginCreate(context));
|
||||
component->setInitialProperties(object.get(), initialProperties);
|
||||
if (auto props = compPriv->state.requiredProperties()) {
|
||||
requiredPropertiesFromComponent = props;
|
||||
requiredPropertiesFromComponent.setTag(HadTopLevelRequired::Yes);
|
||||
}
|
||||
q->setInitialState(object.get());
|
||||
if (requiredPropertiesFromComponent && !requiredPropertiesFromComponent->isEmpty()) {
|
||||
for (auto unsetRequiredProperty: std::as_const(*requiredPropertiesFromComponent))
|
||||
errors << QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
|
||||
} else {
|
||||
compPriv->completeCreate();
|
||||
result = object.release();
|
||||
progress = QQmlIncubatorPrivate::Completed;
|
||||
}
|
||||
changeStatus(calculateStatus());
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Incubate objects for \a msecs, or until there are no more objects to incubate.
|
||||
*/
|
||||
|
@ -672,12 +704,18 @@ setInitialProperties can mark properties set there as no longer required.
|
|||
*/
|
||||
RequiredProperties *QQmlIncubatorPrivate::requiredProperties()
|
||||
{
|
||||
return creator->requiredProperties();
|
||||
if (creator)
|
||||
return creator->requiredProperties();
|
||||
else
|
||||
return requiredPropertiesFromComponent.data();
|
||||
}
|
||||
|
||||
bool QQmlIncubatorPrivate::hadTopLevelRequiredProperties() const
|
||||
{
|
||||
return creator->componentHadTopLevelRequiredProperties();
|
||||
if (creator)
|
||||
return creator->componentHadTopLevelRequiredProperties();
|
||||
else
|
||||
return requiredPropertiesFromComponent.tag() == HadTopLevelRequired::Yes;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -52,6 +52,14 @@ public:
|
|||
|
||||
|
||||
QPointer<QObject> result;
|
||||
enum HadTopLevelRequired : bool {No = 0, Yes = 1};
|
||||
/* TODO: unify with Creator pointer once QTBUG-108760 is implemented
|
||||
though we don't acutally own the properties here; if we ever end up
|
||||
with a use case for async incubation of C++ types, we however could
|
||||
not rely on the component to still exist during incubation, and
|
||||
would need to store a copy of the required properties instead
|
||||
*/
|
||||
QTaggedPointer<RequiredProperties, HadTopLevelRequired> requiredPropertiesFromComponent;
|
||||
QQmlGuardedContextData rootContext;
|
||||
QQmlEnginePrivate *enginePriv;
|
||||
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
|
||||
|
@ -70,6 +78,7 @@ public:
|
|||
|
||||
void forceCompletion(QQmlInstantiationInterrupt &i);
|
||||
void incubate(QQmlInstantiationInterrupt &i);
|
||||
void incubateCppBasedComponent(QQmlComponent *component, QQmlContext *context);
|
||||
RequiredProperties *requiredProperties();
|
||||
bool hadTopLevelRequiredProperties() const;
|
||||
};
|
||||
|
|
|
@ -138,6 +138,7 @@ private slots:
|
|||
void boundComponent();
|
||||
void loadFromModule_data();
|
||||
void loadFromModule();
|
||||
void loadFromModuleThenCreateWithIncubator();
|
||||
void loadFromModuleFailures_data();
|
||||
void loadFromModuleFailures();
|
||||
void loadFromModuleRequired();
|
||||
|
@ -1328,6 +1329,29 @@ void tst_qqmlcomponent::loadFromModule()
|
|||
name);
|
||||
}
|
||||
|
||||
struct CallVerifyingIncubtor : QQmlIncubator
|
||||
{
|
||||
void setInitialState(QObject *) { setInitialStateCalled = true; }
|
||||
void statusChanged(QQmlIncubator::Status status) { lastStatus = status; }
|
||||
|
||||
QQmlIncubator::Status lastStatus = QQmlIncubator::Null;
|
||||
bool setInitialStateCalled = false;
|
||||
};
|
||||
|
||||
void tst_qqmlcomponent::loadFromModuleThenCreateWithIncubator()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
QQmlComponent comp(&engine);
|
||||
comp.loadFromModule("QtQuick", "Rectangle");
|
||||
CallVerifyingIncubtor incubator;
|
||||
comp.create(incubator);
|
||||
std::unique_ptr<QObject> object { incubator.object() };
|
||||
QVERIFY(incubator.setInitialStateCalled);
|
||||
QVERIFY(incubator.isReady());
|
||||
QCOMPARE(incubator.lastStatus, QQmlIncubator::Ready);
|
||||
QCOMPARE(object->metaObject()->className(), "QQuickRectangle");
|
||||
}
|
||||
|
||||
void tst_qqmlcomponent::loadFromModuleFailures_data()
|
||||
{
|
||||
|
||||
|
|
Loading…
Reference in New Issue