forked from qt-creator/qt-creator
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: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -201,6 +201,13 @@ Rectangle {
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
TableView.editDelegate: CollectionDetailsEditDelegate {
|
||||
anchors {
|
||||
top: itemText.top
|
||||
left: itemText.left
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "default"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "collectiondetails.h"
|
||||
|
||||
#include <utils/span.h>
|
||||
#include <qqml.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
@@ -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>("DataType");
|
||||
qmlRegisterUncreatableType<CollectionDetails>("CollectionDetails", 1, 0, "DataType", "Enum type");
|
||||
}
|
||||
|
||||
CollectionDetails &CollectionDetails::operator=(const CollectionDetails &other)
|
||||
{
|
||||
CollectionDetails value(other);
|
||||
|
||||
@@ -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<QJsonObject> 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:
|
||||
|
||||
@@ -100,6 +100,7 @@ QHash<int, QByteArray> 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user