diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/qmltc/qmltccodewriter.cpp | 1 | ||||
-rw-r--r-- | tools/qmltc/qmltccompiler.cpp | 23 | ||||
-rw-r--r-- | tools/qmltc/qmltccompiler.h | 11 | ||||
-rw-r--r-- | tools/qmltc/qmltccompilerpieces.h | 32 | ||||
-rw-r--r-- | tools/qmltc/qmltcoutputir.h | 6 |
5 files changed, 60 insertions, 13 deletions
diff --git a/tools/qmltc/qmltccodewriter.cpp b/tools/qmltc/qmltccodewriter.cpp index afdfd78d7e..7c9958e215 100644 --- a/tools/qmltc/qmltccodewriter.cpp +++ b/tools/qmltc/qmltccodewriter.cpp @@ -323,6 +323,7 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type) QmltcCodeWriter::write(code, type.baselineCtor); QmltcCodeWriter::write(code, type.init); QmltcCodeWriter::write(code, type.endInit); + QmltcCodeWriter::write(code, type.setComplexBindings); QmltcCodeWriter::write(code, type.beginClass); QmltcCodeWriter::write(code, type.completeComponent); QmltcCodeWriter::write(code, type.finalizeComponent); diff --git a/tools/qmltc/qmltccompiler.cpp b/tools/qmltc/qmltccompiler.cpp index 9a38cca06c..31140e5281 100644 --- a/tools/qmltc/qmltccompiler.cpp +++ b/tools/qmltc/qmltccompiler.cpp @@ -188,6 +188,7 @@ void QmltcCompiler::compileType( current.init.access = QQmlJSMetaMethod::Protected; current.beginClass.access = QQmlJSMetaMethod::Protected; current.endInit.access = QQmlJSMetaMethod::Protected; + current.setComplexBindings.access = QQmlJSMetaMethod::Protected; current.completeComponent.access = QQmlJSMetaMethod::Protected; current.finalizeComponent.access = QQmlJSMetaMethod::Protected; current.handleOnCompleted.access = QQmlJSMetaMethod::Protected; @@ -200,6 +201,8 @@ void QmltcCompiler::compileType( current.beginClass.returnType = u"void"_s; current.endInit.name = u"QML_endInit"_s; current.endInit.returnType = u"void"_s; + current.setComplexBindings.name = u"QML_setComplexBindings"_s; + current.setComplexBindings.returnType = u"void"_s; current.completeComponent.name = u"QML_completeComponent"_s; current.completeComponent.returnType = u"void"_s; current.finalizeComponent.name = u"QML_finalizeComponent"_s; @@ -217,6 +220,7 @@ void QmltcCompiler::compileType( current.init.parameterList = { creator, engine, ctxtdata, finalizeFlag }; current.beginClass.parameterList = { creator, finalizeFlag }; current.endInit.parameterList = { creator, engine, finalizeFlag }; + current.setComplexBindings.parameterList = { creator, engine, finalizeFlag }; current.completeComponent.parameterList = { creator, finalizeFlag }; current.finalizeComponent.parameterList = { creator, finalizeFlag }; current.handleOnCompleted.parameterList = { creator, finalizeFlag }; @@ -225,6 +229,7 @@ void QmltcCompiler::compileType( current.init.parameterList = { creator, engine, ctxtdata }; current.beginClass.parameterList = { creator }; current.endInit.parameterList = { creator, engine }; + current.setComplexBindings.parameterList = { creator, engine }; current.completeComponent.parameterList = { creator }; current.finalizeComponent.parameterList = { creator }; current.handleOnCompleted.parameterList = { creator }; @@ -266,6 +271,7 @@ void QmltcCompiler::compileType( auto postponedQmlContextSetup = generator.generate_initCode(current, type); generator.generate_endInitCode(current, type); + generator.generate_setComplexBindingsCode(current, type); generator.generate_beginClassCode(current, type); generator.generate_completeComponentCode(current, type); generator.generate_finalizeComponentCode(current, type); @@ -281,9 +287,8 @@ static Iterator partitionBindings(Iterator first, Iterator last) // later point, so we should sort or partition the range. we do a stable // partition since the relative order of binding evaluation affects the UI return std::stable_partition(first, last, [](const QQmlJSMetaPropertyBinding &b) { - // we want script bindings to be at the end, so do the negation of "is - // script binding" - return b.bindingType() != QQmlJSMetaPropertyBinding::Script; + // we want complex bindings to be at the end, so do the negation + return !QmltcCompiler::isComplexBinding(b); }); } @@ -1227,10 +1232,10 @@ void QmltcCompiler::compileScriptBinding(QmltcType ¤t, slotMethod.type = QQmlJSMetaMethod::Slot; current.functions << std::move(slotMethod); - current.endInit.body << u"QObject::connect(" + This_signal + u", " - + QmltcCodeGenerator::wrap_qOverload(slotParameters, - u"&" + objectClassName_signal + u"::" - + signalName) + current.setComplexBindings.body + << u"QObject::connect(" + This_signal + u", " + + QmltcCodeGenerator::wrap_qOverload( + slotParameters, u"&" + objectClassName_signal + u"::" + signalName) + u", " + This_slot + u", &" + objectClassName_slot + u"::" + slotName + u");"; }; @@ -1269,7 +1274,7 @@ void QmltcCompiler::compileScriptBinding(QmltcType ¤t, } QmltcCodeGenerator::generate_createBindingOnProperty( - ¤t.endInit.body, generate_callCompilationUnit(m_urlMethodName), + ¤t.setComplexBindings.body, generate_callCompilationUnit(m_urlMethodName), u"this"_s, // NB: always using enclosing object as a scope for the binding static_cast<qsizetype>(objectType->ownRuntimeFunctionIndex(binding.scriptIndex())), bindingTarget, // binding target @@ -1314,7 +1319,7 @@ void QmltcCompiler::compileScriptBinding(QmltcType ¤t, // TODO: this could be dropped if QQmlEngine::setContextForObject() is // done before currently generated C++ object is constructed - current.endInit.body << bindingSymbolName + u".reset(new QPropertyChangeHandler<" + current.setComplexBindings.body << bindingSymbolName + u".reset(new QPropertyChangeHandler<" + bindingFunctorName + u">(" + QmltcCodeGenerator::wrap_privateClass(accessor.name, *actualProperty) + u"->" + bindableString + u"().onValueChanged(" + bindingFunctorName + u"(" diff --git a/tools/qmltc/qmltccompiler.h b/tools/qmltc/qmltccompiler.h index 67b21bad25..ede4d3c6a0 100644 --- a/tools/qmltc/qmltccompiler.h +++ b/tools/qmltc/qmltccompiler.h @@ -36,6 +36,17 @@ public: ~QmltcCompiler(); + /*! \internal + + Returns \c true if \a binding is considered complex by the compiler + (requires special code generation) + */ + static bool isComplexBinding(const QQmlJSMetaPropertyBinding &binding) + { + // TODO: translation bindings (once supported) are also complex? + return binding.bindingType() == QQmlJSMetaPropertyBinding::Script; + } + private: QString m_url; // QML input file url QmltcTypeResolver *m_typeResolver = nullptr; diff --git a/tools/qmltc/qmltccompilerpieces.h b/tools/qmltc/qmltccompilerpieces.h index ebdd5d048c..cbee19485d 100644 --- a/tools/qmltc/qmltccompilerpieces.h +++ b/tools/qmltc/qmltccompilerpieces.h @@ -40,6 +40,8 @@ struct QmltcCodeGenerator const QString &baseInstructionArgs, const QString &childInstructionArgs) const; inline void generate_endInitCode(QmltcType ¤t, const QQmlJSScope::ConstPtr &type) const; + inline void generate_setComplexBindingsCode(QmltcType ¤t, + const QQmlJSScope::ConstPtr &type) const; inline void generate_interfaceCallCode(QmltcMethod *function, const QQmlJSScope::ConstPtr &type, const QString &interfaceName, @@ -251,6 +253,8 @@ inline decltype(auto) QmltcCodeGenerator::generate_initCode(QmltcType ¤t, .arg(current.beginClass.name); current.init.body << QStringLiteral(" %1(creator, engine, /* finalize */ true);") .arg(current.endInit.name); + current.init.body << QStringLiteral(" %1(creator, engine, /* finalize */ true);") + .arg(current.setComplexBindings.name); current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);") .arg(current.completeComponent.name); current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);") @@ -398,6 +402,34 @@ inline void QmltcCodeGenerator::generate_endInitCode(QmltcType ¤t, /*! \internal + Generates \a{current.setComplexBindings}'s code. The setComplexBindings + method creates complex bindings (such as script bindings). Additionally, the + QML document root's setComplexBindings calls setComplexBindings methods of + all the necessary QML types within the document. +*/ +inline void +QmltcCodeGenerator::generate_setComplexBindingsCode(QmltcType ¤t, + const QQmlJSScope::ConstPtr &type) const +{ + using namespace Qt::StringLiterals; + + // QML_setComplexBindings()'s parameters: + // * QQmltcObjectCreationHelper* creator + // * QQmlEngine* engine + // * bool canFinalize [optional, when document root] + const bool isDocumentRoot = type == visitor->result(); + current.setComplexBindings.body << u"Q_UNUSED(creator);"_s; + current.setComplexBindings.body << u"Q_UNUSED(engine);"_s; + if (isDocumentRoot) + current.setComplexBindings.body << u"Q_UNUSED(canFinalize);"_s; + + generate_qmltcInstructionCallCode(¤t.setComplexBindings, type, + u"engine, /* finalize */ false"_s, u"creator, engine"_s); +} + +/*! + \internal + A generic helper function that generates interface code boilerplate, adding it to a passed \a function. This is a building block used to generate e.g. QQmlParserStatus API calls. diff --git a/tools/qmltc/qmltcoutputir.h b/tools/qmltc/qmltcoutputir.h index df4395232d..6e49636980 100644 --- a/tools/qmltc/qmltcoutputir.h +++ b/tools/qmltc/qmltcoutputir.h @@ -108,14 +108,12 @@ struct QmltcType QmltcCtor externalCtor {}; // calls basicCtor, calls init QmltcMethod init {}; // starts object initialization (context setup), calls finalize QmltcMethod beginClass {}; // calls QQmlParserStatus::classBegin() - QmltcMethod endInit {}; // ends object initialization (with binding setup) + QmltcMethod endInit {}; // ends object initialization (with "simple" bindings setup) + QmltcMethod setComplexBindings {}; // sets up "complex" (e.g. script) bindings QmltcMethod completeComponent {}; // calls QQmlParserStatus::componentComplete() QmltcMethod finalizeComponent {}; // calls QQmlFinalizerHook::componentFinalized() QmltcMethod handleOnCompleted {}; // calls Component.onCompleted - // TODO: add a separate special member function to set script bindings in a - // separate step - std::optional<QmltcDtor> dtor {}; // member functions: methods, signals and slots |