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 <miikka.heikkinen@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2023-01-27 10:14:06 +02:00
parent 6ccef0cc29
commit 003ae4db87
5 changed files with 196 additions and 35 deletions

View File

@@ -146,11 +146,15 @@ StudioControls.ComboBox {
if (!comboBox.__isCompleted) if (!comboBox.__isCompleted)
return return
let inputValue = comboBox.editText let inputText = comboBox.editText
let inputValue = inputText;
let index = comboBox.find(inputValue) let index = comboBox.find(inputText)
if (index !== -1) if (index !== -1) {
inputValue = comboBox.textAt(index) let modelIdx = comboBox.model.index(index)
inputValue = comboBox.valueRole
? comboBox.model.data(modelIdx, comboBox.valueRole)
: comboBox.textAt(index)
}
comboBox.backendValue.value = inputValue comboBox.backendValue.value = inputValue
@@ -167,6 +171,18 @@ StudioControls.ComboBox {
if (comboBox.manualMapping) if (comboBox.manualMapping)
return 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) { switch (comboBox.valueType) {
case ComboBox.ValueType.String: case ComboBox.ValueType.String:
comboBox.backendValue.value = comboBox.currentText comboBox.backendValue.value = comboBox.currentText

View File

@@ -23,6 +23,8 @@ Item {
property real __actionIndicatorWidth: StudioTheme.Values.squareComponentWidth property real __actionIndicatorWidth: StudioTheme.Values.squareComponentWidth
property real __actionIndicatorHeight: StudioTheme.Values.height property real __actionIndicatorHeight: StudioTheme.Values.height
property string typeFilter: "QtQuick3D.Material" property string typeFilter: "QtQuick3D.Material"
property string textRole: "IdAndNameRole"
property string valueRole: "IdRole"
property int activatedReason: ComboBox.ActivatedReason.Other property int activatedReason: ComboBox.ActivatedReason.Other
property bool delegateHover: false property bool delegateHover: false
@@ -49,8 +51,9 @@ Item {
actionIndicatorVisible: false actionIndicatorVisible: false
typeFilter: editableListView.typeFilter typeFilter: editableListView.typeFilter
editText: modelData
initialModelData: modelData initialModelData: modelData
textRole: editableListView.textRole
valueRole: editableListView.valueRole
implicitWidth: StudioTheme.Values.singleControlColumnWidth implicitWidth: StudioTheme.Values.singleControlColumnWidth
width: implicitWidth width: implicitWidth
@@ -58,20 +61,22 @@ Item {
if (itemFilterComboBox.focus) if (itemFilterComboBox.focus)
myColumn.currentIndex = index myColumn.currentIndex = index
if (itemFilterComboBox.empty && itemFilterComboBox.editText !== "") { var curValue = itemFilterComboBox.availableValue()
if (itemFilterComboBox.empty && curValue !== "") {
myRepeater.dirty = false myRepeater.dirty = false
editableListView.add(itemFilterComboBox.editText) editableListView.add(curValue)
} }
} }
onCompressedActivated: { onCompressedActivated: function(index, reason) {
editableListView.activatedReason = reason editableListView.activatedReason = reason
if (itemFilterComboBox.empty && itemFilterComboBox.editText !== "") { var curValue = itemFilterComboBox.availableValue()
if (itemFilterComboBox.empty && curValue) {
myRepeater.dirty = false myRepeater.dirty = false
editableListView.add(itemFilterComboBox.editText) editableListView.add(curValue)
} else { } 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*\.?)+)/ } validator: RegExpValidator { regExp: /(^[a-z_]\w*|^[A-Z]\w*\.{1}([a-z_]\w*\.?)+)/ }
actionIndicatorVisible: false actionIndicatorVisible: false
typeFilter: editableListView.typeFilter typeFilter: editableListView.typeFilter
textRole: editableListView.textRole
valueRole: editableListView.valueRole
implicitWidth: StudioTheme.Values.singleControlColumnWidth implicitWidth: StudioTheme.Values.singleControlColumnWidth
width: implicitWidth width: implicitWidth
onFocusChanged: { onFocusChanged: {
if (dummyComboBox.editText !== "") var curValue = dummyComboBox.availableValue()
editableListView.add(dummyComboBox.editText) if (curValue !== "")
editableListView.add(curValue)
} }
onCompressedActivated: { onCompressedActivated: {
editableListView.activatedReason = reason editableListView.activatedReason = reason
if (dummyComboBox.editText !== "") var curValue = dummyComboBox.availableValue()
editableListView.add(dummyComboBox.editText) if (curValue !== "")
editableListView.add(curValue)
else else
editableListView.replace(dummyComboBox.myIndex, dummyComboBox.editText) editableListView.replace(dummyComboBox.myIndex, curValue)
} }
onHoverChanged: editableListView.delegateHover = dummyComboBox.hover onHoverChanged: editableListView.delegateHover = dummyComboBox.hover

View File

@@ -14,7 +14,9 @@ StudioControls.ComboBox {
property bool __isCompleted: false property bool __isCompleted: false
editable: true editable: true
model: itemFilterModel.itemModel model: itemFilterModel
textRole: "IdRole"
valueRole: "IdRole"
HelperWidgets.ItemFilterModel { HelperWidgets.ItemFilterModel {
id: itemFilterModel id: itemFilterModel
@@ -23,12 +25,48 @@ StudioControls.ComboBox {
Component.onCompleted: { Component.onCompleted: {
comboBox.__isCompleted = true 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 // 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. // 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) if (comboBox.currentIndex === -1)
comboBox.editText = comboBox.initialModelData 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
}
} }

View File

@@ -6,14 +6,28 @@
#include <abstractview.h> #include <abstractview.h>
#include <model.h> #include <model.h>
#include <nodemetainfo.h> #include <nodemetainfo.h>
#include <qmlmodelnodeproxy.h>
#include "variantproperty.h"
#include <QFileDialog> #include <QFileDialog>
#include <QDirIterator> #include <QDirIterator>
#include <qmlmodelnodeproxy.h> #include <QMetaEnum>
ItemFilterModel::ItemFilterModel(QObject *parent) : using namespace QmlDesigner;
QObject(parent), m_typeFilter("QtQuick.Item"), m_lock(false), m_selectionOnly(false)
QHash<int, QByteArray> 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<Roles>();
for (int i = 0; i < roleEnum.keyCount(); i++)
m_roles.insert(roleEnum.value(i), roleEnum.key(i));
}
} }
void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend) void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend)
@@ -22,7 +36,7 @@ void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend)
auto modelNodeBackendObject = modelNodeBackend.value<QObject*>(); auto modelNodeBackendObject = modelNodeBackend.value<QObject*>();
const auto backendObjectCasted = const auto backendObjectCasted =
qobject_cast<const QmlDesigner::QmlModelNodeProxy *>(modelNodeBackendObject); qobject_cast<const QmlModelNodeProxy *>(modelNodeBackendObject);
if (backendObjectCasted) if (backendObjectCasted)
m_modelNode = backendObjectCasted->qmlObjectNode().modelNode(); m_modelNode = backendObjectCasted->qmlObjectNode().modelNode();
@@ -62,19 +76,79 @@ void ItemFilterModel::registerDeclarativeType()
qmlRegisterType<ItemFilterModel>("HelperWidgets",2,0,"ItemFilterModel"); qmlRegisterType<ItemFilterModel>("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<int, QByteArray> 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() void ItemFilterModel::setupModel()
{ {
if (!m_modelNode.isValid() || !m_modelNode.view()->isAttached()) if (!m_modelNode.isValid() || !m_modelNode.view()->isAttached())
return; return;
m_lock = true; beginResetModel();
m_model.clear(); m_modelInternalIds.clear();
const auto nodes = m_selectionOnly ? m_modelNode.view()->selectedModelNodes() const auto nodes = m_selectionOnly ? m_modelNode.view()->selectedModelNodes()
: m_modelNode.view()->allModelNodes(); : m_modelNode.view()->allModelNodes();
@@ -82,15 +156,22 @@ void ItemFilterModel::setupModel()
auto base = m_modelNode.model()->metaInfo(m_typeFilter.toUtf8()); auto base = m_modelNode.model()->metaInfo(m_typeFilter.toUtf8());
for (const QmlDesigner::ModelNode &node : nodes) { for (const QmlDesigner::ModelNode &node : nodes) {
if (node.hasId() && node.metaInfo().isBasedOn(base)) if (node.hasId() && node.metaInfo().isBasedOn(base))
m_model.append(node.id()); m_modelInternalIds.append(node.internalId());
} }
m_lock = false; endResetModel();
emit itemModelChanged(); emit itemModelChanged();
} }
QStringList ItemFilterModel::itemModel() const 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;
} }

View File

@@ -6,12 +6,13 @@
#include <qmlitemnode.h> #include <qmlitemnode.h>
#include <QDir> #include <QDir>
#include <QHash>
#include <QObject> #include <QObject>
#include <QStringList> #include <QStringList>
#include <QUrl> #include <QUrl>
#include <QtQml> #include <QtQml>
class ItemFilterModel : public QObject class ItemFilterModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
@@ -21,6 +22,13 @@ class ItemFilterModel : public QObject
Q_PROPERTY(bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged) Q_PROPERTY(bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged)
public: public:
enum Roles {
IdRole = Qt::UserRole + 1,
NameRole,
IdAndNameRole
};
Q_ENUM(Roles)
explicit ItemFilterModel(QObject *parent = nullptr); explicit ItemFilterModel(QObject *parent = nullptr);
void setModelNodeBackend(const QVariant &modelNodeBackend); void setModelNodeBackend(const QVariant &modelNodeBackend);
@@ -33,6 +41,14 @@ public:
static void registerDeclarativeType(); 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<int,QByteArray> roleNames() const override;
signals: signals:
void modelNodeBackendChanged(); void modelNodeBackendChanged();
void itemModelChanged(); void itemModelChanged();
@@ -40,13 +56,14 @@ signals:
private: private:
QVariant modelNodeBackend() const; QVariant modelNodeBackend() const;
QmlDesigner::ModelNode modelNodeForRow(const int &row) const;
private: private:
QString m_typeFilter; QString m_typeFilter;
bool m_lock; QList<qint32> m_modelInternalIds;
QStringList m_model;
QmlDesigner::ModelNode m_modelNode; QmlDesigner::ModelNode m_modelNode;
bool m_selectionOnly; bool m_selectionOnly;
static QHash<int, QByteArray> m_roles;
}; };
QML_DECLARE_TYPE(ItemFilterModel) QML_DECLARE_TYPE(ItemFilterModel)