aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp2
-rw-r--r--src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp5
-rw-r--r--src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc11
-rw-r--r--tests/auto/qml/qmltc/QmltcTests/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qmltc/QmltcTests/qtbug120700_main.qml22
-rw-r--r--tests/auto/qml/qmltc/tst_qmltc.cpp38
-rw-r--r--tests/auto/qml/qmltc/tst_qmltc.h1
-rw-r--r--tools/qmltc/qmltccodewriter.cpp46
-rw-r--r--tools/qmltc/qmltccodewriter.h1
-rw-r--r--tools/qmltc/qmltccompiler.cpp111
-rw-r--r--tools/qmltc/qmltccompilerpieces.cpp3
-rw-r--r--tools/qmltc/qmltccompilerpieces.h25
-rw-r--r--tools/qmltc/qmltcoutputir.h27
13 files changed, 275 insertions, 19 deletions
diff --git a/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
index eda9009bb7..0afbcbf0bf 100644
--- a/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
+++ b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
@@ -22,7 +22,7 @@ class HelloWorld : public QObject
Q_PROPERTY(QString hello WRITE setHello READ hello BINDABLE bindableHello)
public:
- HelloWorld(QQmlEngine* engine, QObject* parent = nullptr);
+ HelloWorld(QQmlEngine* engine, QObject* parent = nullptr, [[maybe_unused]] qxp::function_ref<void(PropertyInitializer&)> initializer = [](PropertyInitializer&){});
Q_SIGNALS:
void created();
diff --git a/src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp b/src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp
index 7bda70f985..8c2706531b 100644
--- a/src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp
+++ b/src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp
@@ -53,7 +53,10 @@ void tst_qmltc_examples::app()
QQmlEngine e;
QQuickWindow window;
- QScopedPointer<QmltcExample::myApp> documentRoot(new QmltcExample::myApp(&e));
+ QScopedPointer<QmltcExample::myApp> documentRoot(
+ new QmltcExample::myApp(&e, nullptr, [](auto& component){
+ component.setWidth(800);
+ }));
documentRoot->setParentItem(window.contentItem());
window.setHeight(documentRoot->height());
diff --git a/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc b/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc
index b512be1b7e..dc525f3428 100644
--- a/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc
+++ b/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc
@@ -113,9 +113,14 @@ Unlike in the case of QQmlComponent instantiation, the output of qmltc, being
C++ code, is used directly by the application. Generally, constructing a new
object in C++ is equivalent to creating a new object through
QQmlComponent::create(). Once created, the object could be manipulated from C++
-or, for example, combined with QQuickWindow to be drawn on screen. Given a
-\c{myApp.qml} file, the application code (in both cases) would typically look
-like this:
+or, for example, combined with QQuickWindow to be drawn on screen.
+
+Additionally, the constructor for a qmltc object can be provided with
+with a callback to set up initial values for the component's
+properties.
+
+Given a \c{myApp.qml} file, the application code (in both cases) would
+typically look like this:
\if defined(onlinedocs)
\tab {generated-c++}{tab-qqmlcomponent}{Using QQmlComponent}{checked}
diff --git a/tests/auto/qml/qmltc/QmltcTests/CMakeLists.txt b/tests/auto/qml/qmltc/QmltcTests/CMakeLists.txt
index a7093d2ac7..4b0fb63796 100644
--- a/tests/auto/qml/qmltc/QmltcTests/CMakeLists.txt
+++ b/tests/auto/qml/qmltc/QmltcTests/CMakeLists.txt
@@ -50,6 +50,8 @@ set(qml_sources
qtbug103956/MainComponent.qml
qtbug103956/qtbug103956_main.qml
+ qtbug120700_main.qml
+
signalHandlers.qml
javaScriptFunctions.qml
changingBindings.qml
diff --git a/tests/auto/qml/qmltc/QmltcTests/qtbug120700_main.qml b/tests/auto/qml/qmltc/QmltcTests/qtbug120700_main.qml
new file mode 100644
index 0000000000..2f356b456f
--- /dev/null
+++ b/tests/auto/qml/qmltc/QmltcTests/qtbug120700_main.qml
@@ -0,0 +1,22 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QmltcTests 1.0
+
+TypeWithSpecialProperties {
+ id: myWindow
+ required property int someValue
+
+ property alias someValueAlias: myWindow.someValue
+ property int someValueBinding: someValue + 1
+
+ property bool wasSomeValueChanged: false
+
+ property int someComplexValueThatWillBeSet: { return 5 }
+ property int someComplexValueThatWillNotBeSet: { return 5 }
+
+ //QTBUG-114403: onValueChanged should not trigger when setting
+ //the initial values.
+ onSomeValueChanged: { wasSomeValueChanged = true; }
+}
diff --git a/tests/auto/qml/qmltc/tst_qmltc.cpp b/tests/auto/qml/qmltc/tst_qmltc.cpp
index b1b55a377b..816e3b1d34 100644
--- a/tests/auto/qml/qmltc/tst_qmltc.cpp
+++ b/tests/auto/qml/qmltc/tst_qmltc.cpp
@@ -21,6 +21,7 @@
#include "qjsvalueassignments.h"
#include "extensiontypebindings.h"
#include "qtbug103956_main.h"
+#include "qtbug120700_main.h"
#include "nonstandardinclude.h"
#include "specialproperties.h"
#include "regexpbindings.h"
@@ -159,6 +160,8 @@ void tst_qmltc::initTestCase()
QUrl("qrc:/qt/qml/QmltcTests/qtbug103956/MainComponent.qml"),
QUrl("qrc:/qt/qml/QmltcTests/qtbug103956/qtbug103956_main.qml"),
+ QUrl("qrc:/qt/qml/QmltcTests/qtbug120700_main.qml"),
+
QUrl("qrc:/qt/qml/QmltcTests/signalHandlers.qml"),
QUrl("qrc:/qt/qml/QmltcTests/javaScriptFunctions.qml"),
QUrl("qrc:/qt/qml/QmltcTests/changingBindings.qml"),
@@ -832,6 +835,41 @@ void tst_qmltc::visibleAliasMethods()
QCOMPARE(created.firstComponent()->setMe(), true);
}
+// QTBUG-120700
+void tst_qmltc::customInitialization()
+{
+ int valueToTest = 10;
+
+ QQmlEngine e;
+ PREPEND_NAMESPACE(qtbug120700_main)
+ created(&e, nullptr, [valueToTest](auto& component) {
+ component.setSomeValue(valueToTest);
+ component.setSomeComplexValueThatWillBeSet(valueToTest);
+ component.setZ(static_cast<double>(valueToTest));
+ });
+
+ // QTBUG-114403: onValueChanged should have not been triggered
+ // when setting the initial value for the property.
+ // If this is true then the handler was called.
+ QCOMPARE(created.wasSomeValueChanged(), false);
+
+ // someComplexValueThatWillBeSet is set through a binding in the
+ // QML code, but is initialized when the instance is created.
+ // The bindings, which is generally set after the custom
+ // initialization was perfomed, should not overwrite the initial
+ // value that the user provided.
+ // On the other side, someComplexValueThatWillNotBeSet should
+ // still respect the original binding as an initial value for it
+ // was not provided.
+ QCOMPARE(created.someComplexValueThatWillBeSet(), valueToTest);
+ QCOMPARE(created.someComplexValueThatWillNotBeSet(), 5);
+
+ QCOMPARE(created.someValue(), valueToTest);
+ QCOMPARE(created.someValueAlias(), valueToTest);
+ QCOMPARE(created.someValueBinding(), valueToTest + 1);
+ QCOMPARE(created.bindableZ().value(), static_cast<double>(valueToTest));
+}
+
// QTBUG-104094
void tst_qmltc::nonStandardIncludesInsideModule()
{
diff --git a/tests/auto/qml/qmltc/tst_qmltc.h b/tests/auto/qml/qmltc/tst_qmltc.h
index c89ba12656..7bc8136b8c 100644
--- a/tests/auto/qml/qmltc/tst_qmltc.h
+++ b/tests/auto/qml/qmltc/tst_qmltc.h
@@ -35,6 +35,7 @@ private slots:
void jsvalueAssignments();
void extensionTypeBindings();
void visibleAliasMethods(); // QTBUG-103956
+ void customInitialization(); // QTBUG-120700
void nonStandardIncludesInsideModule(); // QTBUG-104094
void specialProperties();
void regexpBindings();
diff --git a/tools/qmltc/qmltccodewriter.cpp b/tools/qmltc/qmltccodewriter.cpp
index 67ffcd6b0b..d4eb57606c 100644
--- a/tools/qmltc/qmltccodewriter.cpp
+++ b/tools/qmltc/qmltccodewriter.cpp
@@ -118,6 +118,7 @@ void QmltcCodeWriter::writeGlobalHeader(QmltcOutputWrapper &code, const QString
code.rawAppendToHeader(u"#include <QtCore/qproperty.h>");
code.rawAppendToHeader(u"#include <QtCore/qobject.h>");
code.rawAppendToHeader(u"#include <QtCore/qcoreapplication.h>");
+ code.rawAppendToHeader(u"#include <QtCore/qxpfunctional.h>");
code.rawAppendToHeader(u"#include <QtQml/qqmlengine.h>");
code.rawAppendToHeader(u"#include <QtCore/qurl.h>"); // used in engine execution
code.rawAppendToHeader(u"#include <QtQml/qqml.h>"); // used for attached properties
@@ -160,6 +161,48 @@ void QmltcCodeWriter::writeGlobalHeader(QmltcOutputWrapper &code, const QString
}
}
+void QmltcCodeWriter::write(QmltcOutputWrapper &code,
+ const QmltcPropertyInitializer &propertyInitializer,
+ const QmltcType &wrappedType)
+{
+ code.rawAppendToHeader(u"class " + propertyInitializer.name + u" {");
+
+ {
+ {
+ [[maybe_unused]] QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
+
+ code.rawAppendToHeader(u"friend class " + wrappedType.cppType + u";");
+ }
+
+ code.rawAppendToHeader(u"public:"_s);
+
+ [[maybe_unused]] QmltcOutputWrapper::MemberNameScope typeScope(&code, propertyInitializer.name);
+ {
+ [[maybe_unused]] QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
+
+ write(code, propertyInitializer.constructor);
+ code.rawAppendToHeader(u""); // blank line
+
+ for (const auto &propertySetter : propertyInitializer.propertySetters) {
+ write(code, propertySetter);
+ }
+ }
+
+ code.rawAppendToHeader(u""); // blank line
+ code.rawAppendToHeader(u"private:"_s);
+
+ {
+ [[maybe_unused]] QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
+
+ write(code, propertyInitializer.component);
+ write(code, propertyInitializer.initializedCache);
+ }
+ }
+
+ code.rawAppendToHeader(u"};"_s);
+ code.rawAppendToHeader(u""); // blank line
+}
+
void QmltcCodeWriter::writeGlobalFooter(QmltcOutputWrapper &code, const QString &sourcePath,
const QString &outNamespace)
{
@@ -291,6 +334,9 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type,
code.rawAppendToHeader(u"/* External C++ API */");
code.rawAppendToHeader(u"public:", -1);
+ if (!type.propertyInitializer.name.isEmpty())
+ write(code, type.propertyInitializer, type);
+
// NB: when non-document root, the externalCtor won't be public - but we
// really don't care about the output format of such types
if (!type.ignoreInit && type.externalCtor.access == QQmlJSMetaMethod::Public) {
diff --git a/tools/qmltc/qmltccodewriter.h b/tools/qmltc/qmltccodewriter.h
index 04446f4c4e..b45773eef9 100644
--- a/tools/qmltc/qmltccodewriter.h
+++ b/tools/qmltc/qmltccodewriter.h
@@ -27,6 +27,7 @@ struct QmltcCodeWriter
static void write(QmltcOutputWrapper &code, const QmltcDtor &dtor);
static void write(QmltcOutputWrapper &code, const QmltcVariable &var);
static void write(QmltcOutputWrapper &code, const QmltcProperty &prop);
+ static void write(QmltcOutputWrapper &code, const QmltcPropertyInitializer &propertyInitializer, const QmltcType& wrappedType);
private:
static void writeUrl(QmltcOutputWrapper &code, const QmltcMethod &urlMethod); // special
diff --git a/tools/qmltc/qmltccompiler.cpp b/tools/qmltc/qmltccompiler.cpp
index 1ad0fdaf20..f0371bcaf1 100644
--- a/tools/qmltc/qmltccompiler.cpp
+++ b/tools/qmltc/qmltccompiler.cpp
@@ -248,6 +248,17 @@ void QmltcCompiler::compileType(
current.finalizeComponent.access = QQmlJSMetaMethod::Protected;
current.handleOnCompleted.access = QQmlJSMetaMethod::Protected;
+ current.propertyInitializer.name = u"PropertyInitializer"_s;
+ current.propertyInitializer.constructor.access = QQmlJSMetaMethod::Public;
+ current.propertyInitializer.constructor.name = current.propertyInitializer.name;
+ current.propertyInitializer.constructor.parameterList = {
+ QmltcVariable(u"%1&"_s.arg(current.cppType), u"component"_s)
+ };
+ current.propertyInitializer.component.cppType = current.cppType + u"&";
+ current.propertyInitializer.component.name = u"component"_s;
+ current.propertyInitializer.initializedCache.cppType = u"QSet<QString>"_s;
+ current.propertyInitializer.initializedCache.name = u"initializedCache"_s;
+
current.baselineCtor.name = current.cppType;
current.externalCtor.name = current.cppType;
current.init.name = u"QML_init"_s;
@@ -267,16 +278,26 @@ void QmltcCompiler::compileType(
QmltcVariable creator(u"QQmltcObjectCreationHelper*"_s, u"creator"_s);
QmltcVariable engine(u"QQmlEngine*"_s, u"engine"_s);
QmltcVariable parent(u"QObject*"_s, u"parent"_s, u"nullptr"_s);
+ QmltcVariable initializedCache(
+ u"[[maybe_unused]] const QSet<QString>&"_s,
+ u"initializedCache"_s,
+ u"{}"_s
+ );
QmltcVariable ctxtdata(u"const QQmlRefPointer<QQmlContextData>&"_s, u"parentContext"_s);
QmltcVariable finalizeFlag(u"bool"_s, u"canFinalize"_s);
current.baselineCtor.parameterList = { parent };
current.endInit.parameterList = { creator, engine };
- current.setComplexBindings.parameterList = { creator, engine };
+ current.setComplexBindings.parameterList = { creator, engine, initializedCache };
current.handleOnCompleted.parameterList = { creator };
if (documentRoot || inlineComponent) {
- current.externalCtor.parameterList = { engine, parent };
- current.init.parameterList = { creator, engine, ctxtdata, finalizeFlag };
+ QmltcVariable initializer(
+ u"[[maybe_unused]] qxp::function_ref<void(%1&)>"_s.arg(current.propertyInitializer.name),
+ u"initializer"_s,
+ u"[](%1&){}"_s.arg(current.propertyInitializer.name));
+
+ current.externalCtor.parameterList = { engine, parent, initializer };
+ current.init.parameterList = { creator, engine, ctxtdata, finalizeFlag, initializer };
current.beginClass.parameterList = { creator, finalizeFlag };
current.completeComponent.parameterList = { creator, finalizeFlag };
current.finalizeComponent.parameterList = { creator, finalizeFlag };
@@ -314,7 +335,7 @@ void QmltcCompiler::compileType(
// now call init
current.externalCtor.body << current.init.name
+ u"(&creator, engine, QQmlContextData::get(engine->rootContext()), /* "
- u"endInit */ true);";
+ u"endInit */ true, initializer);";
} else {
current.externalCtor.body << u"// not document root:"_s;
// just call init, we don't do any setup here otherwise
@@ -362,6 +383,82 @@ static Iterator partitionBindings(Iterator first, Iterator last)
});
}
+// Populates the propertyInitializer of the current type based on the
+// available properties.
+//
+// A propertyInitializer is a generated class that provides a
+// restricted interface that only allows setting property values and
+// internally keep tracks of which properties where actually set,
+// intended to be used to allow the user to set up the initial values
+// when creating an instance of a component.
+//
+// For each property of the current type that is known, is not private
+// and is writable, a setter method is generated.
+// Each setter method knows how to set a specific property, so as to
+// provide a strongly typed interface to property setting, as if the
+// relevant C++ type was used directly.
+//
+// Each setter uses the write method for the proprerty when available
+// and otherwise falls back to a the more generic
+// `QObject::setProperty` for properties where a WRITE method is not
+// available or in scope.
+static void compilePropertyInitializer(QmltcType &current, const QQmlJSScope::ConstPtr &type) {
+ static auto isFromExtension = [](const QQmlJSMetaProperty &property, const QQmlJSScope::ConstPtr &scope) {
+ return scope->ownerOfProperty(scope, property.propertyName()).extensionSpecifier != QQmlJSScope::NotExtension;
+ };
+
+ current.propertyInitializer.constructor.initializerList << u"component{component}"_s;
+
+ auto properties = type->properties().values();
+ for (auto& property: properties) {
+ if (property.index() == -1) continue;
+ if (property.isPrivate()) continue;
+ if (!property.isWritable() || qIsReferenceTypeList(property)) continue;
+
+ const QString name = property.propertyName();
+
+ current.propertyInitializer.propertySetters.emplace_back();
+ auto& compiledSetter = current.propertyInitializer.propertySetters.back();
+
+ compiledSetter.userVisible = true;
+ compiledSetter.returnType = u"void"_s;
+ compiledSetter.name = QmltcPropertyData(property).write;
+ compiledSetter.parameterList.emplaceBack(
+ QQmlJSUtils::constRefify(getUnderlyingType(property)), name + u"_", QString()
+ );
+
+ if (QQmlJSUtils::bindablePropertyHasDefaultAccessor(property, QQmlJSUtils::PropertyAccessor_Write)) {
+ compiledSetter.body << u"%1.%2().setValue(%3_);"_s.arg(
+ current.propertyInitializer.component.name, property.bindable(), name);
+ } else if (property.write().isEmpty() || isFromExtension(property, type)) {
+ // We can end here if a WRITE method is not available or
+ // if the method is available but not in this scope, so
+ // that we fallback to the string-based setters..
+ //
+ // For example, types that makes use of QML_EXTENDED
+ // types, will have the extension types properties
+ // available and with a WRITE method, but the WRITE method
+ // will not be available to the extended type, from C++,
+ // as the type does not directly inherit from the
+ // extension type.
+ //
+ // We specifically scope `setProperty` to `QObject` as
+ // certain types might have shadowed the method.
+ // For example, in QtQuick, some types have a property
+ // called `property` with a `setProperty` WRITE method
+ // that will produce the shadowing.
+ compiledSetter.body << u"%1.QObject::setProperty(\"%2\", QVariant::fromValue(%2_));"_s.arg(
+ current.propertyInitializer.component.name, name);
+ } else {
+ compiledSetter.body << u"%1.%2(%3_);"_s.arg(
+ current.propertyInitializer.component.name, property.write(), name);
+ }
+
+ compiledSetter.body << u"%1.insert(\"%2\");"_s.arg(
+ current.propertyInitializer.initializedCache.name, name);
+ }
+}
+
void QmltcCompiler::compileTypeElements(QmltcType &current, const QQmlJSScope::ConstPtr &type)
{
// compile components of a type:
@@ -404,6 +501,7 @@ void QmltcCompiler::compileTypeElements(QmltcType &current, const QQmlJSScope::C
auto bindings = type->ownPropertyBindingsInQmlIROrder();
partitionBindings(bindings.begin(), bindings.end());
+ compilePropertyInitializer(current, type);
compileBinding(current, bindings.begin(), bindings.end(), type, { type });
}
@@ -1777,9 +1875,12 @@ void QmltcCompiler::compileScriptBinding(QmltcType &current,
current.children << compileScriptBindingPropertyChangeHandler(
binding, objectType, m_urlMethodName, bindingFunctorName, objectClassName);
+ current.setComplexBindings.body << u"if (!%1.contains(\"%2\"))"_s.arg(
+ current.propertyInitializer.initializedCache.name, propertyName);
+
// TODO: this could be dropped if QQmlEngine::setContextForObject() is
// done before currently generated C++ object is constructed
- current.setComplexBindings.body << bindingSymbolName + u".reset(new QPropertyChangeHandler<"
+ current.setComplexBindings.body << u" "_s + bindingSymbolName + u".reset(new QPropertyChangeHandler<"
+ bindingFunctorName + u">("
+ QmltcCodeGenerator::wrap_privateClass(accessor.name, *actualProperty)
+ u"->" + bindableString + u"().onValueChanged(" + bindingFunctorName + u"("
diff --git a/tools/qmltc/qmltccompilerpieces.cpp b/tools/qmltc/qmltccompilerpieces.cpp
index 4c6c93eaa2..bdb71cff4c 100644
--- a/tools/qmltc/qmltccompilerpieces.cpp
+++ b/tools/qmltc/qmltccompilerpieces.cpp
@@ -237,7 +237,8 @@ void QmltcCodeGenerator::generate_createBindingOnProperty(
}
*block += prologue;
- *block << value + u"->" + bindable + u"().setBinding(" + createBindingForBindable + u");";
+ *block << u"if (!initializedCache.contains(\"%1\"))"_s.arg(p.propertyName());
+ *block << u" "_s + value + u"->" + bindable + u"().setBinding(" + createBindingForBindable + u");";
*block += epilogue;
} else {
QString createBindingForNonBindable =
diff --git a/tools/qmltc/qmltccompilerpieces.h b/tools/qmltc/qmltccompilerpieces.h
index 06708b2165..3252f19e86 100644
--- a/tools/qmltc/qmltccompilerpieces.h
+++ b/tools/qmltc/qmltccompilerpieces.h
@@ -152,14 +152,17 @@ struct QmltcCodeGenerator
/*!
\internal
- Generates \a{current.init}'s code. The init method sets up a QQmlContext for
- the object and (in case \a type is a document root) calls other object
- creation methods in a well-defined order:
+ Generates \a{current.init}'s code. The init method sets up a
+ QQmlContext for the object and (in case \a type is a document
+ root) calls other object creation methods, and a user-provided
+ initialization callback, in a well-defined order:
1. current.beginClass
2. current.endInit
- 3. current.completeComponent
- 4. current.finalizeComponent
- 5. current.handleOnCompleted
+ 3. user-provided initialization function
+ 4. current.setComplexBindings
+ 5. current.completeComponent
+ 6. current.finalizeComponent
+ 7. current.handleOnCompleted
This function returns a QScopeGuard with the final instructions that have to
be generated at a later point, once everything else is compiled.
@@ -294,8 +297,14 @@ inline decltype(auto) QmltcCodeGenerator::generate_initCode(QmltcType &current,
.arg(current.beginClass.name);
current.init.body << QStringLiteral(" %1(creator, engine);")
.arg(current.endInit.name);
- current.init.body << QStringLiteral(" %1(creator, engine);")
- .arg(current.setComplexBindings.name);
+
+ current.init.body << QStringLiteral(" {");
+ current.init.body << QStringLiteral(" PropertyInitializer propertyInitializer(*this);");
+ current.init.body << QStringLiteral(" initializer(propertyInitializer);");
+ current.init.body << QStringLiteral(" %1(creator, engine, propertyInitializer.initializedCache);").arg(current.setComplexBindings.name);
+ current.init.body << QStringLiteral(" }");
+
+
current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);")
.arg(current.completeComponent.name);
current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);")
diff --git a/tools/qmltc/qmltcoutputir.h b/tools/qmltc/qmltcoutputir.h
index bed5a2037f..eb608f8749 100644
--- a/tools/qmltc/qmltcoutputir.h
+++ b/tools/qmltc/qmltcoutputir.h
@@ -92,6 +92,29 @@ struct QmltcDtor : QmltcMethodBase
{
};
+// Represents a generated class that knows how to set the public,
+// writable properties of a compiled QML -> C++ type.
+// This is generally intended to be available for the root of the
+// document to allow the user to set the initial values for
+// properties, when creating a component, with support for strong
+// typing.
+struct QmltcPropertyInitializer {
+ QString name;
+
+ QmltcCtor constructor;
+
+ // A member containing a reference to the object for which the
+ // properties should be set.
+ QmltcVariable component;
+
+ // A member containing a cache of properties that were actually
+ // set that can be referenced later..
+ QmltcVariable initializedCache;
+
+ // Setter methods for each property.
+ QList<QmltcMethod> propertySetters;
+};
+
// Represents QML -> C++ compiled type
struct QmltcType
{
@@ -131,6 +154,10 @@ struct QmltcType
// needed for singletons
std::optional<QmltcMethod> staticCreate{};
+
+ // A proxy class that provides a restricted interface that only
+ // allows setting the properties of the type.
+ QmltcPropertyInitializer propertyInitializer{};
};
// Represents whole QML program, compiled to C++