From 003ae4db879a5643412bb7a8a539ec80f42da72b Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Fri, 27 Jan 2023 10:14:06 +0200 Subject: [PATCH] QmlDesigner: Show the material name in the property editor The material name for the property editor's material field is presented in the following format: MaterialName [MaterialId] Task-number: QDS-8663 Change-Id: I59fdfcb52ecb2ce9a1079ae20b7e2d748bbc1d61 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../imports/HelperWidgets/ComboBox.qml | 26 ++++- .../HelperWidgets/EditableListView.qml | 33 ++++-- .../HelperWidgets/ListViewComboBox.qml | 44 +++++++- .../propertyeditor/itemfiltermodel.cpp | 105 ++++++++++++++++-- .../propertyeditor/itemfiltermodel.h | 23 +++- 5 files changed, 196 insertions(+), 35 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml index 139672e4721..b22b1e4c2a2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml @@ -146,11 +146,15 @@ StudioControls.ComboBox { if (!comboBox.__isCompleted) return - let inputValue = comboBox.editText - - let index = comboBox.find(inputValue) - if (index !== -1) - inputValue = comboBox.textAt(index) + let inputText = comboBox.editText + let inputValue = inputText; + let index = comboBox.find(inputText) + if (index !== -1) { + let modelIdx = comboBox.model.index(index) + inputValue = comboBox.valueRole + ? comboBox.model.data(modelIdx, comboBox.valueRole) + : comboBox.textAt(index) + } comboBox.backendValue.value = inputValue @@ -167,6 +171,18 @@ StudioControls.ComboBox { if (comboBox.manualMapping) return + if (comboBox.valueRole && comboBox.textRole !== comboBox.valueRole) { + let inputText = comboBox.currentText + let inputValue = comboBox.currentValue + let index = comboBox.find(inputText) + if (index !== -1) { + let modelIdx = comboBox.model.index(index) + inputValue = comboBox.model.data(modelIdx, comboBox.valueRole) + } + comboBox.backendValue.value = inputValue + return + } + switch (comboBox.valueType) { case ComboBox.ValueType.String: comboBox.backendValue.value = comboBox.currentText diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml index 43a53f83a4a..83f2bff6740 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml @@ -23,6 +23,8 @@ Item { property real __actionIndicatorWidth: StudioTheme.Values.squareComponentWidth property real __actionIndicatorHeight: StudioTheme.Values.height property string typeFilter: "QtQuick3D.Material" + property string textRole: "IdAndNameRole" + property string valueRole: "IdRole" property int activatedReason: ComboBox.ActivatedReason.Other property bool delegateHover: false @@ -49,8 +51,9 @@ Item { actionIndicatorVisible: false typeFilter: editableListView.typeFilter - editText: modelData initialModelData: modelData + textRole: editableListView.textRole + valueRole: editableListView.valueRole implicitWidth: StudioTheme.Values.singleControlColumnWidth width: implicitWidth @@ -58,20 +61,22 @@ Item { if (itemFilterComboBox.focus) myColumn.currentIndex = index - if (itemFilterComboBox.empty && itemFilterComboBox.editText !== "") { + var curValue = itemFilterComboBox.availableValue() + if (itemFilterComboBox.empty && curValue !== "") { myRepeater.dirty = false - editableListView.add(itemFilterComboBox.editText) + editableListView.add(curValue) } } - onCompressedActivated: { + onCompressedActivated: function(index, reason) { editableListView.activatedReason = reason - if (itemFilterComboBox.empty && itemFilterComboBox.editText !== "") { + var curValue = itemFilterComboBox.availableValue() + if (itemFilterComboBox.empty && curValue) { myRepeater.dirty = false - editableListView.add(itemFilterComboBox.editText) + editableListView.add(curValue) } else { - editableListView.replace(itemFilterComboBox.myIndex, itemFilterComboBox.editText) + editableListView.replace(itemFilterComboBox.myIndex, curValue) } } @@ -170,21 +175,25 @@ Item { validator: RegExpValidator { regExp: /(^[a-z_]\w*|^[A-Z]\w*\.{1}([a-z_]\w*\.?)+)/ } actionIndicatorVisible: false typeFilter: editableListView.typeFilter + textRole: editableListView.textRole + valueRole: editableListView.valueRole implicitWidth: StudioTheme.Values.singleControlColumnWidth width: implicitWidth onFocusChanged: { - if (dummyComboBox.editText !== "") - editableListView.add(dummyComboBox.editText) + var curValue = dummyComboBox.availableValue() + if (curValue !== "") + editableListView.add(curValue) } onCompressedActivated: { editableListView.activatedReason = reason - if (dummyComboBox.editText !== "") - editableListView.add(dummyComboBox.editText) + var curValue = dummyComboBox.availableValue() + if (curValue !== "") + editableListView.add(curValue) else - editableListView.replace(dummyComboBox.myIndex, dummyComboBox.editText) + editableListView.replace(dummyComboBox.myIndex, curValue) } onHoverChanged: editableListView.delegateHover = dummyComboBox.hover diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml index 733d9c690fd..3f9f9f24f2a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml @@ -14,7 +14,9 @@ StudioControls.ComboBox { property bool __isCompleted: false editable: true - model: itemFilterModel.itemModel + model: itemFilterModel + textRole: "IdRole" + valueRole: "IdRole" HelperWidgets.ItemFilterModel { id: itemFilterModel @@ -23,12 +25,48 @@ StudioControls.ComboBox { Component.onCompleted: { comboBox.__isCompleted = true + resetInitialIndex() + } + + onInitialModelDataChanged: resetInitialIndex() + onValueRoleChanged: resetInitialIndex() + onModelChanged: resetInitialIndex() + onTextRoleChanged: resetInitialIndex() + + function resetInitialIndex() { + let currentSelectedDataIndex = -1 // Workaround for proper initialization. Use the initial modelData value and search for it // in the model. If nothing was found, set the editText to the initial modelData. - comboBox.currentIndex = comboBox.find(comboBox.initialModelData) - + if (textRole === valueRole) { + currentSelectedDataIndex = comboBox.find(comboBox.initialModelData) + } else { + for (let i = 0; i < comboBox.count; ++i) { + let movingModelIndex = model.index(i) + let movingModelValueData = model.data(movingModelIndex, valueRole) + if (movingModelValueData === initialModelData) { + currentSelectedDataIndex = i + break + } + } + } + comboBox.currentIndex = currentSelectedDataIndex if (comboBox.currentIndex === -1) comboBox.editText = comboBox.initialModelData } + + function currentData(role = valueRole) { + if (comboBox.currentIndex !== -1) { + let currentModelIndex = model.index(currentIndex) + return model.data(currentModelIndex, role) + } + return comboBox.editText + } + + function availableValue() { + if (comboBox.currentIndex !== -1 && currentValue !== "") + return currentValue + + return comboBox.editText + } } diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp index 46976374942..6bf922c0bdf 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp @@ -6,14 +6,28 @@ #include #include #include +#include +#include "variantproperty.h" #include #include -#include +#include -ItemFilterModel::ItemFilterModel(QObject *parent) : - QObject(parent), m_typeFilter("QtQuick.Item"), m_lock(false), m_selectionOnly(false) +using namespace QmlDesigner; + +QHash ItemFilterModel::m_roles; + +ItemFilterModel::ItemFilterModel(QObject *parent) + : QAbstractListModel(parent) + , m_typeFilter("QtQuick.Item") + , m_selectionOnly(false) { + if (m_roles.empty()) { + m_roles = QAbstractListModel::roleNames(); + QMetaEnum roleEnum = QMetaEnum::fromType(); + for (int i = 0; i < roleEnum.keyCount(); i++) + m_roles.insert(roleEnum.value(i), roleEnum.key(i)); + } } void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend) @@ -22,7 +36,7 @@ void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend) auto modelNodeBackendObject = modelNodeBackend.value(); const auto backendObjectCasted = - qobject_cast(modelNodeBackendObject); + qobject_cast(modelNodeBackendObject); if (backendObjectCasted) m_modelNode = backendObjectCasted->qmlObjectNode().modelNode(); @@ -62,19 +76,79 @@ void ItemFilterModel::registerDeclarativeType() qmlRegisterType("HelperWidgets",2,0,"ItemFilterModel"); } -QVariant ItemFilterModel::modelNodeBackend() const +QModelIndex ItemFilterModel::index(int row, int column, const QModelIndex &parent) const { - return QVariant(); + return QAbstractListModel::index(row, column, parent); } +int ItemFilterModel::rowCount(const QModelIndex &) const +{ + return m_modelInternalIds.size(); +} + +QVariant ItemFilterModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return {}; + + ModelNode node = modelNodeForRow(index.row()); + + QVariant value; + switch (role) { + case IdRole: + value = node.id(); + break; + case NameRole: + value = node.variantProperty("objectName").value(); + break; + case IdAndNameRole: + value = QString("%1 [%2]").arg( + node.variantProperty("objectName").value().toString() + ,node.id()); + break; + default: + value = node.id(); + break; + } + + return value; +} + +// TODO: Handle model data manipulation here. +bool ItemFilterModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + return QAbstractListModel::setData(index, value, role); +} + +QHash ItemFilterModel::roleNames() const +{ + return m_roles; +} + +QVariant ItemFilterModel::modelNodeBackend() const +{ + return {}; +} + +ModelNode ItemFilterModel::modelNodeForRow(const int &row) const +{ + if (row < 0 || row >= m_modelInternalIds.size()) + return {}; + + AbstractView *view = m_modelNode.view(); + if (!view || !view->model()) + return {}; + + return view->modelNodeForInternalId(m_modelInternalIds.at(row)); +} void ItemFilterModel::setupModel() { if (!m_modelNode.isValid() || !m_modelNode.view()->isAttached()) return; - m_lock = true; - m_model.clear(); + beginResetModel(); + m_modelInternalIds.clear(); const auto nodes = m_selectionOnly ? m_modelNode.view()->selectedModelNodes() : m_modelNode.view()->allModelNodes(); @@ -82,15 +156,22 @@ void ItemFilterModel::setupModel() auto base = m_modelNode.model()->metaInfo(m_typeFilter.toUtf8()); for (const QmlDesigner::ModelNode &node : nodes) { if (node.hasId() && node.metaInfo().isBasedOn(base)) - m_model.append(node.id()); + m_modelInternalIds.append(node.internalId()); } - m_lock = false; - + endResetModel(); emit itemModelChanged(); } QStringList ItemFilterModel::itemModel() const { - return m_model; + AbstractView *view = m_modelNode.view(); + if (!view || !view->model()) + return {}; + + QStringList retval; + for (const auto &internalId : std::as_const(m_modelInternalIds)) + retval << view->modelNodeForInternalId(internalId).id(); + + return retval; } diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h index e93c6695856..54b29f1fd74 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h @@ -6,12 +6,13 @@ #include #include +#include #include #include #include #include -class ItemFilterModel : public QObject +class ItemFilterModel : public QAbstractListModel { Q_OBJECT @@ -21,6 +22,13 @@ class ItemFilterModel : public QObject Q_PROPERTY(bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged) public: + enum Roles { + IdRole = Qt::UserRole + 1, + NameRole, + IdAndNameRole + }; + Q_ENUM(Roles) + explicit ItemFilterModel(QObject *parent = nullptr); void setModelNodeBackend(const QVariant &modelNodeBackend); @@ -33,6 +41,14 @@ public: static void registerDeclarativeType(); + // Make index accessible for Qml side since it's not accessible by default in QAbstractListModel + Q_INVOKABLE QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override; + Q_INVOKABLE virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; + Q_INVOKABLE virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + Q_INVOKABLE virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + virtual QHash roleNames() const override; + signals: void modelNodeBackendChanged(); void itemModelChanged(); @@ -40,13 +56,14 @@ signals: private: QVariant modelNodeBackend() const; + QmlDesigner::ModelNode modelNodeForRow(const int &row) const; private: QString m_typeFilter; - bool m_lock; - QStringList m_model; + QList m_modelInternalIds; QmlDesigner::ModelNode m_modelNode; bool m_selectionOnly; + static QHash m_roles; }; QML_DECLARE_TYPE(ItemFilterModel)