From 2322313baf79d3d124665fe88d64b7995eb51879 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 12 Jul 2023 09:21:45 +0200 Subject: [PATCH] QmlDesigner: Remove typeName usage in binding editor Task-number: QDS-10266 Change-Id: I91232c1296c4ed3b3148af9053d3db0f43a08e24 Reviewed-by: Reviewed-by: Aleksei German --- .../bindingeditor/bindingeditor.cpp | 120 ++++++---- .../components/bindingeditor/bindingeditor.h | 4 +- .../bindingeditor/bindingeditordialog.cpp | 4 +- .../bindingeditor/bindingeditordialog.h | 6 +- .../connectioneditor/connectionviewwidget.cpp | 16 +- .../qmldesigner/designercore/include/model.h | 1 + .../designercore/include/nodemetainfo.h | 1 + .../designercore/metainfo/nodemetainfo.cpp | 25 ++ .../qmldesigner/designercore/model/model.cpp | 10 + .../projectstorage/commontypecache.h | 214 +++++++++--------- .../unittests/metainfo/nodemetainfo-test.cpp | 45 ++++ 11 files changed, 279 insertions(+), 167 deletions(-) diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp index 8c8d0911793..10e8181d8d5 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp @@ -91,10 +91,7 @@ void BindingEditor::setBackendValue(const QVariant &backendValue) const ModelNode node = propertyEditorValue->modelNode(); if (node.isValid()) { - m_backendValueTypeName = node.metaInfo() - .property(propertyEditorValue->name()) - .propertyType() - .simplifiedTypeName(); + m_backendValueType = node.metaInfo().property(propertyEditorValue->name()).propertyType(); QString nodeId = node.id(); if (nodeId.isEmpty()) @@ -102,9 +99,11 @@ void BindingEditor::setBackendValue(const QVariant &backendValue) m_targetName = nodeId + "." + propertyEditorValue->name(); - if (m_backendValueTypeName == "alias" || m_backendValueTypeName == "unknown") + if (!m_backendValueType || m_backendValueType.isAlias()) { if (QmlObjectNode::isValidQmlObjectNode(node)) - m_backendValueTypeName = QmlObjectNode(node).instanceType(propertyEditorValue->name()); + m_backendValueType = node.model()->metaInfo( + QmlObjectNode(node).instanceType(propertyEditorValue->name())); + } } emit backendValueChanged(); @@ -135,7 +134,7 @@ void BindingEditor::setStateModelNode(const QVariant &stateModelNode) m_modelNode = m_stateModelNode.value(); if (m_modelNode.isValid()) - m_backendValueTypeName = "bool"; + m_backendValueType = m_modelNode.model()->boolMetaInfo(); emit stateModelNodeChanged(); } @@ -153,9 +152,9 @@ void BindingEditor::setModelNode(const ModelNode &modelNode) m_modelNode = modelNode; } -void BindingEditor::setBackendValueTypeName(const TypeName &backendValueTypeName) +void BindingEditor::setBackendValueType(const NodeMetaInfo &backendValueType) { - m_backendValueTypeName = backendValueTypeName; + m_backendValueType = backendValueType; emit backendValueChanged(); } @@ -165,65 +164,80 @@ void BindingEditor::setTargetName(const QString &target) m_targetName = target; } +namespace { +template +bool isType(const Tuple &types, const TypeName &compareType) +{ + return std::apply([&](const auto &...type) { return ((type == compareType) || ...); }, types); +} + +template +bool isType(const TypeName &first, const TypeName &second, const Tuple &...types) +{ + return ((types == first) || ...) && ((types == second) || ...); +} + +bool compareTypes(const NodeMetaInfo &sourceType, const NodeMetaInfo &targetType) +{ + if constexpr (useProjectStorage()) { + return targetType.isVariant() || sourceType.isVariant() || targetType == sourceType + || (targetType.isNumber() && sourceType.isNumber()) + || (targetType.isColor() && sourceType.isColor()) + || (targetType.isString() && sourceType.isString()); + } else { + const TypeName source = sourceType.simplifiedTypeName(); + const TypeName target = targetType.simplifiedTypeName(); + + static constexpr auto variantTypes = std::make_tuple("alias", "unknown", "variant", "var"); + + return isType(variantTypes, target) || isType(variantTypes, source) + || targetType == sourceType || isType(target, source, "double", "real", "int") + || isType(target, source, "QColor", "color") + || isType(target, source, "QString", "string"); + } +} +} // namespace + void BindingEditor::prepareBindings() { - if (!m_modelNode.isValid() || m_backendValueTypeName.isEmpty()) + if (!m_modelNode.isValid() || !m_backendValueType) { return; + } const QList allNodes = m_modelNode.view()->allModelNodes(); QList bindings; - const QVarLengthArray variantTypes = {"alias", "unknown", "variant", "var"}; - const QVarLengthArray numericTypes = {"double", "real", "int"}; - const QVarLengthArray colorTypes = {"QColor", "color"}; - const QVarLengthArray stringTypes = {"QString", "string"}; - - auto isVariant = [&variantTypes](const TypeName &compareType) { - return variantTypes.contains(compareType); - }; - auto isNumeric = [&numericTypes](const TypeName &compareType) { - return numericTypes.contains(compareType); - }; - auto isColor = [&colorTypes](const TypeName &compareType) { - return colorTypes.contains(compareType); - }; - auto isString = [&stringTypes](const TypeName &compareType) { - return stringTypes.contains(compareType); - }; - - auto compareTypes = [&](const TypeName &targetType, const TypeName &sourceType) { - return isVariant(targetType) || isVariant(sourceType) || (targetType == sourceType) - || (isNumeric(targetType) && isNumeric(sourceType)) - || (isColor(targetType) && isColor(sourceType)) - || (isString(targetType) && isString(sourceType)); - }; - for (const auto &objnode : allNodes) { BindingEditorDialog::BindingOption binding; for (const auto &property : objnode.metaInfo().properties()) { - const TypeName &propertyTypeName = property.propertyType().simplifiedTypeName(); + const auto &propertyType = property.propertyType(); - if (compareTypes(m_backendValueTypeName, propertyTypeName)) + if (compareTypes(m_backendValueType, propertyType)) { binding.properties.append(QString::fromUtf8(property.name())); + } } //dynamic properties: for (const BindingProperty &bindingProperty : objnode.bindingProperties()) { if (bindingProperty.isValid()) { if (bindingProperty.isDynamic()) { - const TypeName dynamicTypeName = bindingProperty.dynamicTypeName(); - if (compareTypes(m_backendValueTypeName, dynamicTypeName)) + auto model = bindingProperty.model(); + const auto dynamicType = model->metaInfo(bindingProperty.dynamicTypeName()); + if (compareTypes(m_backendValueType, dynamicType)) { binding.properties.append(QString::fromUtf8(bindingProperty.name())); + } } } } for (const VariantProperty &variantProperty : objnode.variantProperties()) { if (variantProperty.isValid()) { if (variantProperty.isDynamic()) { - const TypeName dynamicTypeName = variantProperty.dynamicTypeName(); - if (compareTypes(m_backendValueTypeName, dynamicTypeName)) + auto model = variantProperty.model(); + const auto dynamicType = model->metaInfo(variantProperty.dynamicTypeName()); + if (compareTypes(m_backendValueType, dynamicType)) { binding.properties.append(QString::fromUtf8(variantProperty.name())); + } } } } @@ -244,10 +258,11 @@ void BindingEditor::prepareBindings() BindingEditorDialog::BindingOption binding; for (const auto &property : metaInfo.properties()) { - const TypeName propertyTypeName = property.propertyType().typeName(); + const auto propertyType = property.propertyType(); - if (compareTypes(m_backendValueTypeName, propertyTypeName)) + if (compareTypes(m_backendValueType, propertyType)) { binding.properties.append(QString::fromUtf8(property.name())); + } } if (!binding.properties.isEmpty()) { @@ -260,15 +275,24 @@ void BindingEditor::prepareBindings() } if (!bindings.isEmpty() && !m_dialog.isNull()) - m_dialog->setAllBindings(bindings, m_backendValueTypeName); + m_dialog->setAllBindings(bindings, m_backendValueType); } void BindingEditor::updateWindowName() { - if (!m_dialog.isNull() && !m_backendValueTypeName.isEmpty()) { - const QString targetString = " [" - + (m_targetName.isEmpty() ? QString() : (m_targetName + ": ")) - + QString::fromUtf8(m_backendValueTypeName) + "]"; + if (!m_dialog.isNull() && m_backendValueType) { + QString targetString; + if constexpr (useProjectStorage()) { + auto exportedTypeNames = m_backendValueType.exportedTypeNamesForSourceId( + m_modelNode.model()->fileUrlSourceId()); + if (exportedTypeNames.size()) { + targetString = " [" + (m_targetName.isEmpty() ? QString() : (m_targetName + ": ")) + + exportedTypeNames.front().name.toQString() + "]"; + } + } else { + targetString = " [" + (m_targetName.isEmpty() ? QString() : (m_targetName + ": ")) + + QString::fromUtf8(m_backendValueType.simplifiedTypeName()) + "]"; + } m_dialog->setWindowTitle(m_dialog->defaultTitle() + targetString); } diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h index 59ce036c18c..52aa0884f69 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h @@ -49,7 +49,7 @@ public: //3. modelnode + backend value type name + optional target name void setModelNode(const ModelNode &modelNode); - void setBackendValueTypeName(const TypeName &backendValueTypeName); + void setBackendValueType(const NodeMetaInfo &backendValueType); void setTargetName(const QString &target); Q_INVOKABLE void prepareBindings(); @@ -77,7 +77,7 @@ private: QVariant m_modelNodeBackend; QVariant m_stateModelNode; QmlDesigner::ModelNode m_modelNode; - TypeName m_backendValueTypeName; + NodeMetaInfo m_backendValueType; QString m_targetName; }; diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp index 0cb178603f3..ac5dd615337 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp @@ -79,7 +79,7 @@ void BindingEditorDialog::adjustProperties() m_comboBoxProperty->setCurrentText(property); } -void BindingEditorDialog::setAllBindings(const QList &bindings, const TypeName &type) +void BindingEditorDialog::setAllBindings(const QList &bindings, const NodeMetaInfo &type) { m_lock = true; @@ -118,7 +118,7 @@ void BindingEditorDialog::setupComboBoxes() void BindingEditorDialog::setupCheckBox() { - const bool visible = (m_type == "bool"); + const bool visible = m_type.isBool(); m_checkBoxNot->setVisible(visible); } diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h index ba14a0ee38d..f2995f0a1bf 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h @@ -6,6 +6,8 @@ #include +#include + QT_BEGIN_NAMESPACE class QComboBox; class QCheckBox; @@ -35,7 +37,7 @@ public: void adjustProperties() override; - void setAllBindings(const QList &bindings, const TypeName &type); + void setAllBindings(const QList &bindings, const NodeMetaInfo &type); private: void setupUIComponents(); @@ -53,7 +55,7 @@ private: QCheckBox *m_checkBoxNot = nullptr; QList m_bindings; - TypeName m_type; + NodeMetaInfo m_type; }; } diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp index 5a1fb2df819..8a8845b47fd 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp @@ -194,18 +194,17 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) return; const ModelNode node = property.parentModelNode(); - const TypeName typeName = property.isDynamic() ? property.dynamicTypeName() - : node.metaInfo() - .property(property.name()) - .propertyType() - .typeName(); + auto model = node.model(); + const auto type = property.isDynamic() + ? model->metaInfo(property.dynamicTypeName()) + : node.metaInfo().property(property.name()).propertyType(); const QString targetName = node.displayName() + "." + property.name(); m_bindingEditor->showWidget(); m_bindingEditor->setBindingValue(property.expression()); m_bindingEditor->setModelNode(node); - m_bindingEditor->setBackendValueTypeName(typeName); + m_bindingEditor->setBackendValueType(type); m_bindingEditor->setTargetName(targetName); m_bindingEditor->prepareBindings(); m_bindingEditor->updateWindowName(); @@ -242,11 +241,12 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) return; const QString targetName = node.displayName() + "." + abstractProperty.name(); - + auto model = node.model(); m_dynamicEditor->showWidget(); m_dynamicEditor->setBindingValue(newExpression); m_dynamicEditor->setModelNode(node); - m_dynamicEditor->setBackendValueTypeName(abstractProperty.dynamicTypeName()); + m_dynamicEditor->setBackendValueType( + model->metaInfo(abstractProperty.dynamicTypeName())); m_dynamicEditor->setTargetName(targetName); m_dynamicEditor->prepareBindings(); m_dynamicEditor->updateWindowName(); diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h index d65d075446c..1577fc24319 100644 --- a/src/plugins/qmldesigner/designercore/include/model.h +++ b/src/plugins/qmldesigner/designercore/include/model.h @@ -122,6 +122,7 @@ public: bool hasNodeMetaInfo(const TypeName &typeName, int majorVersion = -1, int minorVersion = -1) const; void setMetaInfo(const MetaInfo &metaInfo); + NodeMetaInfo boolMetaInfo() const; NodeMetaInfo flowViewFlowActionAreaMetaInfo() const; NodeMetaInfo flowViewFlowDecisionMetaInfo() const; NodeMetaInfo flowViewFlowItemMetaInfo() const; diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h index 6bafb04794c..050524ee1ec 100644 --- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h +++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h @@ -127,6 +127,7 @@ public: bool isInteger() const; bool isLayoutable() const; bool isListOrGridView() const; + bool isNumber() const; bool isQmlComponent() const; bool isQtMultimediaSoundEffect() const; bool isQtObject() const; diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index 1c104cce4f7..1ed1e110e5a 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -2240,6 +2240,31 @@ bool NodeMetaInfo::isListOrGridView() const } } +bool NodeMetaInfo::isNumber() const +{ + if constexpr (useProjectStorage()) { + if (!isValid()) { + return false; + } + + using namespace Storage::Info; + auto intId = m_projectStorage->builtinTypeId(); + auto uintId = m_projectStorage->builtinTypeId(); + auto floatId = m_projectStorage->builtinTypeId(); + auto doubleId = m_projectStorage->builtinTypeId(); + + return isTypeId(m_typeId, intId, uintId, floatId, doubleId); + } else { + if (!isValid()) { + return false; + } + + auto type = simplifiedTypeName(); + + return type == "int" || type == "uint" || type == "float" || type == "double"; + } +} + bool NodeMetaInfo::isQtQuickExtrasPicture() const { if constexpr (useProjectStorage()) { diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 188536c778e..c8ffeb43b12 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -2004,6 +2004,16 @@ void Model::setMetaInfo(const MetaInfo &metaInfo) d->setMetaInfo(metaInfo); } +NodeMetaInfo Model::boolMetaInfo() const +{ + if constexpr (useProjectStorage()) { + using namespace Storage::Info; + return createNodeMetaInfo(); + } else { + return metaInfo("QML.bool"); + } +} + template NodeMetaInfo Model::createNodeMetaInfo() const { diff --git a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h index 7a5de4ab2b8..183d86c586a 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h @@ -120,6 +120,7 @@ inline constexpr char Texture[] = "Texture"; inline constexpr char TimelineAnimation[] = "TimelineAnimation"; inline constexpr char Timeline[] = "Timeline"; inline constexpr char Transition[] = "Transition"; +inline constexpr char UIntType[] = "uint"; inline constexpr char View3D[] = "View3D"; inline constexpr char Window[] = "Window"; inline constexpr char color[] = "color"; @@ -146,99 +147,99 @@ struct CacheType : public BaseCacheType template class CommonTypeCache { - using CommonTypes - = std::tuple, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType, - CacheType>; + using CommonTypes = std::tuple, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType, + CacheType>; public: CommonTypeCache(const ProjectStorage &projectStorage) @@ -283,30 +284,33 @@ public: { if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) + return typeId(); + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return typeId(); else - return TypeId{}; + static_assert(!std::is_same_v, "built-in type not supported"); + return TypeId{}; } private: diff --git a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp index 2f287e32d6e..4d645ec1681 100644 --- a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp +++ b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp @@ -2300,4 +2300,49 @@ TEST_F(NodeMetaInfo, invalid_source_id_has_no_external_type_names_for_source_id) ASSERT_THAT(exportedTypeNames, IsEmpty()); } + +TEST_F(NodeMetaInfo, float_is_a_number) +{ + auto metaInfo = createMetaInfo("QML-cppnative", "float"); + + bool isType = metaInfo.isNumber(); + + ASSERT_THAT(isType, IsTrue()); +} + +TEST_F(NodeMetaInfo, double_is_a_number) +{ + auto metaInfo = createMetaInfo(qmlModuleId, "double"); + + bool isType = metaInfo.isNumber(); + + ASSERT_THAT(isType, IsTrue()); +} + +TEST_F(NodeMetaInfo, int_is_a_number) +{ + auto metaInfo = createMetaInfo(qmlModuleId, "int"); + + bool isType = metaInfo.isNumber(); + + ASSERT_THAT(isType, IsTrue()); +} + +TEST_F(NodeMetaInfo, uint_is_a_number) +{ + auto metaInfo = createMetaInfo("QML-cppnative", "uint"); + + bool isType = metaInfo.isNumber(); + + ASSERT_THAT(isType, IsTrue()); +} + +TEST_F(NodeMetaInfo, default_is_not_number) +{ + QmlDesigner::NodeMetaInfo metaInfo; + + bool isType = metaInfo.isFloat(); + + ASSERT_THAT(isType, IsFalse()); +} } // namespace