QmlDesigner: Add duplicate control

Add a setting/property to the EditableListView in order to control if
it allows duplicates or not. If duplicates are not allowed it will
disable the items in the ComboBox which are already applied to the
assigned backend property.

Task-number: QDS-6730
Change-Id: I31776fdfb14858c431b40d264e8e709009c517b3
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Ali Kianian <ali.kianian@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Henning Gruendl
2023-05-05 17:08:45 +02:00
committed by Henning Gründl
parent c4ff1921ee
commit 94b019dbe0
4 changed files with 56 additions and 50 deletions

View File

@@ -1,8 +1,9 @@
// Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick 2.15 import QtQuick
import QtQuick.Layouts 1.15 import QtQuick.Layouts
import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme import StudioTheme 1.0 as StudioTheme
@@ -23,11 +24,12 @@ 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 textRole: "idAndName"
property string valueRole: "IdRole" property string valueRole: "id"
property int activatedReason: ComboBox.ActivatedReason.Other property int activatedReason: ComboBox.ActivatedReason.Other
property bool delegateHover: false property bool delegateHover: false
property bool allowDuplicates: true
property string extraButtonIcon: "" // setting this will show an extra button property string extraButtonIcon: "" // setting this will show an extra button
property string extraButtonToolTip: "" property string extraButtonToolTip: ""
@@ -40,11 +42,19 @@ Item {
Layout.preferredWidth: StudioTheme.Values.height * 10 Layout.preferredWidth: StudioTheme.Values.height * 10
Layout.preferredHeight: myColumn.height Layout.preferredHeight: myColumn.height
HelperWidgets.ItemFilterModel {
id: itemFilterModel
typeFilter: root.typeFilter
modelNodeBackendProperty: modelNodeBackend
selectedItems: root.allowDuplicates ? [] : root.model
}
Component { Component {
id: myDelegate id: myDelegate
Row { Row {
property alias comboBox: itemFilterComboBox property alias comboBox: itemFilterComboBox
ListViewComboBox { ListViewComboBox {
id: itemFilterComboBox id: itemFilterComboBox
@@ -54,7 +64,7 @@ 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: root.typeFilter model: itemFilterModel
initialModelData: modelData initialModelData: modelData
textRole: root.textRole textRole: root.textRole
valueRole: root.valueRole valueRole: root.valueRole
@@ -188,7 +198,7 @@ Item {
visible: myRepeater.count === 0 visible: myRepeater.count === 0
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: root.typeFilter model: itemFilterModel
textRole: root.textRole textRole: root.textRole
valueRole: root.valueRole valueRole: root.valueRole
implicitWidth: StudioTheme.Values.singleControlColumnWidth implicitWidth: StudioTheme.Values.singleControlColumnWidth

View File

@@ -1,27 +1,19 @@
// Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.15 import QtQuick
import HelperWidgets 2.0 as HelperWidgets import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls import StudioControls 1.0 as StudioControls
StudioControls.ComboBox { StudioControls.ComboBox {
id: root id: root
property alias typeFilter: itemFilterModel.typeFilter
property var initialModelData property var initialModelData
property bool __isCompleted: false property bool __isCompleted: false
editable: true editable: true
model: itemFilterModel textRole: "id"
textRole: "IdRole" valueRole: "id"
valueRole: "IdRole"
HelperWidgets.ItemFilterModel {
id: itemFilterModel
modelNodeBackendProperty: modelNodeBackend
}
Component.onCompleted: { Component.onCompleted: {
root.__isCompleted = true root.__isCompleted = true

View File

@@ -15,20 +15,11 @@
using namespace QmlDesigner; using namespace QmlDesigner;
QHash<int, QByteArray> ItemFilterModel::m_roles;
ItemFilterModel::ItemFilterModel(QObject *parent) ItemFilterModel::ItemFilterModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_typeFilter("QtQuick.Item") , m_typeFilter("QtQuick.Item")
, m_selectionOnly(false) , m_selectionOnly(false)
{ {}
if (m_roles.empty()) {
m_roles = QAbstractListModel::roleNames();
const 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)
{ {
@@ -64,6 +55,12 @@ void ItemFilterModel::setSelectionOnly(bool value)
emit selectionOnlyChanged(); emit selectionOnlyChanged();
} }
void ItemFilterModel::setSelectedItems(const QStringList &selectedItems)
{
m_selectedItems = selectedItems;
emit selectedItemsChanged();
}
QString ItemFilterModel::typeFilter() const QString ItemFilterModel::typeFilter() const
{ {
return m_typeFilter; return m_typeFilter;
@@ -74,6 +71,11 @@ bool ItemFilterModel::selectionOnly() const
return m_selectionOnly; return m_selectionOnly;
} }
QStringList ItemFilterModel::selectedItems() const
{
return m_selectedItems;
}
void ItemFilterModel::registerDeclarativeType() void ItemFilterModel::registerDeclarativeType()
{ {
qmlRegisterType<ItemFilterModel>("HelperWidgets", 2, 0, "ItemFilterModel"); qmlRegisterType<ItemFilterModel>("HelperWidgets", 2, 0, "ItemFilterModel");
@@ -86,34 +88,34 @@ int ItemFilterModel::rowCount(const QModelIndex &) const
QVariant ItemFilterModel::data(const QModelIndex &index, int role) const QVariant ItemFilterModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid()) if (!index.isValid() || index.row() >= rowCount())
return {}; return {};
const ModelNode node = modelNodeForRow(index.row()); const ModelNode node = modelNodeForRow(index.row());
QVariant value;
switch (role) { switch (role) {
case IdRole: case IdRole:
value = node.id(); return node.id();
break;
case NameRole: case NameRole:
value = node.variantProperty("objectName").value(); return node.variantProperty("objectName").value();
break;
case IdAndNameRole: case IdAndNameRole:
value = QString("%1 [%2]").arg(node.variantProperty("objectName").value().toString(), return QString("%1 [%2]").arg(node.variantProperty("objectName").value().toString(),
node.id()); node.id());
break; case EnabledRole:
return !m_selectedItems.contains(node.id());
default: default:
value = node.id(); return {};
break;
} }
return value;
} }
QHash<int, QByteArray> ItemFilterModel::roleNames() const QHash<int, QByteArray> ItemFilterModel::roleNames() const
{ {
return m_roles; static QHash<int, QByteArray> roleNames{{IdRole, "id"},
{NameRole, "name"},
{IdAndNameRole, "idAndName"},
{EnabledRole, "enabled"}};
return roleNames;
} }
QVariant ItemFilterModel::modelNodeBackend() const QVariant ItemFilterModel::modelNodeBackend() const

View File

@@ -17,25 +17,26 @@ class ItemFilterModel : public QAbstractListModel
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString typeFilter READ typeFilter WRITE setTypeFilter NOTIFY typeFilterChanged) Q_PROPERTY(QString typeFilter READ typeFilter WRITE setTypeFilter NOTIFY typeFilterChanged)
Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend
NOTIFY modelNodeBackendChanged)
Q_PROPERTY(QStringList itemModel READ itemModel NOTIFY itemModelChanged) Q_PROPERTY(QStringList itemModel READ itemModel NOTIFY itemModelChanged)
Q_PROPERTY(bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged) Q_PROPERTY(
bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged)
Q_PROPERTY(QStringList selectedItems READ selectedItems WRITE setSelectedItems NOTIFY
selectedItemsChanged)
public: public:
enum Roles { enum { IdRole = Qt::DisplayRole, NameRole = Qt::UserRole, IdAndNameRole, EnabledRole };
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);
void setTypeFilter(const QString &typeFilter); void setTypeFilter(const QString &typeFilter);
void setSelectionOnly(bool value); void setSelectionOnly(bool value);
void setSelectedItems(const QStringList &selectedItems);
QString typeFilter() const; QString typeFilter() const;
bool selectionOnly() const; bool selectionOnly() const;
QStringList selectedItems() const;
void setupModel(); void setupModel();
QStringList itemModel() const; QStringList itemModel() const;
@@ -51,6 +52,7 @@ signals:
void modelNodeBackendChanged(); void modelNodeBackendChanged();
void itemModelChanged(); void itemModelChanged();
void selectionOnlyChanged(); void selectionOnlyChanged();
void selectedItemsChanged();
private: private:
QVariant modelNodeBackend() const; QVariant modelNodeBackend() const;
@@ -61,7 +63,7 @@ private:
QList<qint32> m_modelInternalIds; QList<qint32> m_modelInternalIds;
QmlDesigner::ModelNode m_modelNode; QmlDesigner::ModelNode m_modelNode;
bool m_selectionOnly; bool m_selectionOnly;
static QHash<int, QByteArray> m_roles; QStringList m_selectedItems;
}; };
QML_DECLARE_TYPE(ItemFilterModel) QML_DECLARE_TYPE(ItemFilterModel)