diff options
-rw-r--r-- | src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp | 2 | ||||
-rw-r--r-- | src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp | 5 | ||||
-rw-r--r-- | src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc | 11 | ||||
-rw-r--r-- | tests/auto/qml/qmltc/QmltcTests/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/auto/qml/qmltc/QmltcTests/qtbug120700_main.qml | 22 | ||||
-rw-r--r-- | tests/auto/qml/qmltc/tst_qmltc.cpp | 38 | ||||
-rw-r--r-- | tests/auto/qml/qmltc/tst_qmltc.h | 1 | ||||
-rw-r--r-- | tools/qmltc/qmltccodewriter.cpp | 46 | ||||
-rw-r--r-- | tools/qmltc/qmltccodewriter.h | 1 | ||||
-rw-r--r-- | tools/qmltc/qmltccompiler.cpp | 111 | ||||
-rw-r--r-- | tools/qmltc/qmltccompilerpieces.cpp | 3 | ||||
-rw-r--r-- | tools/qmltc/qmltccompilerpieces.h | 25 | ||||
-rw-r--r-- | tools/qmltc/qmltcoutputir.h | 27 |
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 ¤t, 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 ¤t, const QQmlJSScope::ConstPtr &type) { // compile components of a type: @@ -404,6 +501,7 @@ void QmltcCompiler::compileTypeElements(QmltcType ¤t, 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 ¤t, 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 ¤t, .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++ |