From bf99d08ca15f2a91b5f4aaa2b7e66a0ca7b4762e Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 18 Oct 2023 11:41:18 +0300 Subject: [PATCH] QmlDesigner: Add edit delegate to the CollectionDetailsView Delegates are added for the Color, Bool, Number, ad String types. The default delegate is string delegate. Task-number: QDS-10989 Change-Id: I7dbaf5451d8be778691e72e18bd3124a754e47b7 Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../CollectionDetailsEditDelegate.qml | 154 ++++++++++++++++++ .../CollectionDetailsView.qml | 7 + .../collectioneditor/collectiondetails.cpp | 37 +++++ .../collectioneditor/collectiondetails.h | 7 + .../collectiondetailsmodel.cpp | 27 ++- .../collectioneditor/collectiondetailsmodel.h | 2 +- .../collectioneditor/collectionview.cpp | 5 + .../collectioneditor/collectionview.h | 2 + src/plugins/qmldesigner/qmldesignerplugin.cpp | 2 + 9 files changed, 239 insertions(+), 4 deletions(-) create mode 100644 share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsEditDelegate.qml diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsEditDelegate.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsEditDelegate.qml new file mode 100644 index 00000000000..d5f85ce49ae --- /dev/null +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsEditDelegate.qml @@ -0,0 +1,154 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import CollectionDetails 1.0 as CollectionDetails +import HelperWidgets 2.0 as HelperWidgets +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme + +Item { + id: root + required property var columnType + + property var __modifier : textEditor + + width: itemColumn.width + height: itemColumn.height + + TableView.onCommit: edit = __modifier.editValue + + Component.onCompleted: { + if (edit && edit !== "") + root.__modifier.editValue = edit + } + + onActiveFocusChanged: { + if (root.activeFocus) + root.__modifier.forceActiveFocus() + } + + Connections { + id: modifierFocusConnection + target: root.__modifier + function onActiveFocusChanged() { + if (!modifierFocusConnection.target.activeFocus) + TableView.commit() + } + } + + Column { + id: itemColumn + + StudioControls.TextField { + id: textEditor + + property alias editValue: textEditor.text + + actionIndicator.visible: false + translationIndicatorVisible: false + enabled: visible + visible: false + } + + StudioControls.RealSpinBox { + id: numberEditor + + property alias editValue: numberEditor.realValue + + actionIndicator.visible: false + enabled: visible + visible: false + + realFrom: -9e9 + realTo: 9e9 + realStepSize: 1.0 + decimals: 6 + } + + StudioControls.CheckBox { + id: boolEditor + + property alias editValue: boolEditor.checked + + actionIndicatorVisible: false + enabled: visible + visible: false + } + + HelperWidgets.ColorPicker { + id: colorEditor + + property alias editValue: colorEditor.color + + width: 100 + enabled: visible + visible: false + } + } + + states: [ + State { + name: "default" + when: columnType !== CollectionDetails.DataType.Boolean + && columnType !== CollectionDetails.DataType.Color + && columnType !== CollectionDetails.DataType.Number + + PropertyChanges { + target: root + __modifier: textEditor + } + + PropertyChanges { + target: textEditor + visible: true + focus: true + } + }, + State { + name: "number" + when: columnType === CollectionDetails.DataType.Number + + PropertyChanges { + target: root + __modifier: numberEditor + } + + PropertyChanges { + target: numberEditor + visible: true + focus: true + } + }, + State { + name: "bool" + when: columnType === CollectionDetails.DataType.Boolean + + PropertyChanges { + target: root + __modifier: boolEditor + } + + PropertyChanges { + target: boolEditor + visible: true + focus: true + } + }, + State { + name: "color" + when: columnType === CollectionDetails.DataType.Color + + PropertyChanges { + target: root + __modifier: colorEditor + } + + PropertyChanges { + target: colorEditor + visible: true + focus: true + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml index aaa4e1e8f2b..d0ac4b0dfed 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml @@ -201,6 +201,13 @@ Rectangle { elide: Text.ElideRight } + TableView.editDelegate: CollectionDetailsEditDelegate { + anchors { + top: itemText.top + left: itemText.left + } + } + states: [ State { name: "default" diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp index 60ab6ab8442..5b84ec55710 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp @@ -4,6 +4,7 @@ #include "collectiondetails.h" #include +#include #include #include @@ -220,6 +221,21 @@ bool CollectionDetails::removeElements(int row, int count) return true; } +bool CollectionDetails::setPropertyValue(int row, int column, const QVariant &value) +{ + if (!d->isValidRowId(row) || !d->isValidColumnId(column)) + return false; + + QJsonObject &element = d->elements[row]; + QVariant currentValue = data(row, column); + + if (value == currentValue) + return false; + + element.insert(d->properties.at(column).name, QJsonValue::fromVariant(value)); + return true; +} + bool CollectionDetails::setPropertyName(int column, const QString &value) { if (!d->isValidColumnId(column)) @@ -316,6 +332,20 @@ CollectionDetails::DataType CollectionDetails::typeAt(int column) const return d->properties.at(column).type; } +CollectionDetails::DataType CollectionDetails::typeAt(int row, int column) const +{ + if (!d->isValidRowId(row) || !d->isValidColumnId(column)) + return {}; + + const QString &propertyName = d->properties.at(column).name; + const QJsonObject &element = d->elements.at(row); + + if (element.contains(propertyName)) + return collectionDataTypeFromJsonValue(element.value(propertyName)); + + return {}; +} + bool CollectionDetails::containsPropertyName(const QString &propertyName) { if (!isValid()) @@ -360,6 +390,13 @@ void CollectionDetails::swap(CollectionDetails &other) d.swap(other.d); } +void CollectionDetails::registerDeclarativeType() +{ + typedef CollectionDetails::DataType DataType; + qRegisterMetaType("DataType"); + qmlRegisterUncreatableType("CollectionDetails", 1, 0, "DataType", "Enum type"); +} + CollectionDetails &CollectionDetails::operator=(const CollectionDetails &other) { CollectionDetails value(other); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h index 20896c67923..33e5552884f 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h @@ -37,8 +37,11 @@ struct CollectionProperty; class CollectionDetails { + Q_GADGET + public: enum class DataType { Unknown, String, Url, Number, Boolean, Image, Color }; + Q_ENUM(DataType) explicit CollectionDetails(); CollectionDetails(const CollectionReference &reference); @@ -57,6 +60,7 @@ public: void insertElementAt(std::optional object, int row = -1); void insertEmptyElements(int row = 0, int count = 1); bool removeElements(int row, int count = 1); + bool setPropertyValue(int row, int column, const QVariant &value); bool setPropertyName(int column, const QString &value); bool forcePropertyType(int column, DataType type, bool force = false); @@ -66,6 +70,7 @@ public: QVariant data(int row, int column) const; QString propertyAt(int column) const; DataType typeAt(int column) const; + DataType typeAt(int row, int column) const; bool containsPropertyName(const QString &propertyName); bool isValid() const; @@ -80,6 +85,8 @@ public: QJsonArray getJsonCollection() const; QString getCsvCollection() const; + static void registerDeclarativeType(); + CollectionDetails &operator=(const CollectionDetails &other); private: diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 896c584be8b..41fdd8102bb 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -100,6 +100,7 @@ QHash CollectionDetailsModel::roleNames() const roles.insert(QAbstractTableModel::roleNames()); roles.insert(SelectedRole, "itemSelected"); roles.insert(DataTypeRole, "dataType"); + roles.insert(ColumnDataTypeRole, "columnType"); } return roles; } @@ -122,11 +123,31 @@ QVariant CollectionDetailsModel::data(const QModelIndex &index, int role) const if (role == SelectedRole) return (index.column() == m_selectedColumn || index.row() == m_selectedRow); - return m_currentCollection.data(index.row(), index.column()); + if (role == DataTypeRole) + return QVariant::fromValue(m_currentCollection.typeAt(index.row(), index.column())); + + if (role == ColumnDataTypeRole) + return QVariant::fromValue(m_currentCollection.typeAt(index.column())); + + if (role == Qt::EditRole) + return m_currentCollection.data(index.row(), index.column()); + + return m_currentCollection.data(index.row(), index.column()).toString(); } -bool CollectionDetailsModel::setData(const QModelIndex &, const QVariant &, int) +bool CollectionDetailsModel::setData(const QModelIndex &index, const QVariant &value, int role) { + if (!index.isValid()) + return {}; + + if (role == Qt::EditRole) { + bool changed = m_currentCollection.setPropertyValue(index.row(), index.column(), value); + if (changed) { + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + } + } + return false; } @@ -189,7 +210,7 @@ Qt::ItemFlags CollectionDetailsModel::flags(const QModelIndex &index) const if (!index.isValid()) return {}; - return {Qt::ItemIsSelectable | Qt::ItemIsEnabled}; + return {Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable}; } QVariant CollectionDetailsModel::headerData(int section, Qt::Orientation orientation, int role) const diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h index ee3805e34bb..220865717a4 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h @@ -22,7 +22,7 @@ class CollectionDetailsModel : public QAbstractTableModel Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged) public: - enum DataRoles { SelectedRole = Qt::UserRole + 1, DataTypeRole }; + enum DataRoles { SelectedRole = Qt::UserRole + 1, DataTypeRole, ColumnDataTypeRole }; explicit CollectionDetailsModel(QObject *parent = nullptr); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index a3ffd72250a..6b0d063081f 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -153,6 +153,11 @@ void CollectionView::addResource(const QUrl &url, const QString &name, const QSt }); } +void CollectionView::registerDeclarativeType() +{ + CollectionDetails::registerDeclarativeType(); +} + void CollectionView::refreshModel() { if (!model()) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h index 6d81d00f064..994105f9745 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h @@ -43,6 +43,8 @@ public: void addResource(const QUrl &url, const QString &name, const QString &type); + static void registerDeclarativeType(); + private: void refreshModel(); NodeMetaInfo jsonCollectionMetaInfo() const; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 40e3b681e48..8c94a53ce49 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -4,6 +4,7 @@ #include "qmldesignerplugin.h" #include "qmldesignertr.h" +#include "collectioneditor/collectionview.h" #include "coreplugin/iwizardfactory.h" #include "designmodecontext.h" #include "designmodewidget.h" @@ -282,6 +283,7 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e //TODO Move registering those types out of the property editor, since they are used also in the states editor Quick2PropertyEditorView::registerQmlTypes(); + CollectionView::registerDeclarativeType(); if (checkEnterpriseLicense()) Core::IWizardFactory::registerFeatureProvider(new EnterpriseFeatureProvider);