2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2015-09-18 15:38:15 +02:00
|
|
|
|
|
|
|
|
#include "dynamicpropertiesmodel.h"
|
2023-08-23 12:12:07 +02:00
|
|
|
#include "dynamicpropertiesitem.h"
|
|
|
|
|
#include "connectioneditorutils.h"
|
|
|
|
|
|
|
|
|
|
#include <abstractproperty.h>
|
|
|
|
|
#include <bindingproperty.h>
|
|
|
|
|
#include <modelfwd.h>
|
|
|
|
|
#include <rewritertransaction.h>
|
|
|
|
|
#include <rewritingexception.h>
|
2022-06-09 17:03:42 +02:00
|
|
|
#include <utils/algorithm.h>
|
2022-07-22 16:46:48 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2023-08-23 12:12:07 +02:00
|
|
|
#include <variantproperty.h>
|
|
|
|
|
#include <qmlchangeset.h>
|
|
|
|
|
#include <qmldesignerconstants.h>
|
|
|
|
|
#include <qmldesignerplugin.h>
|
|
|
|
|
#include <qmlobjectnode.h>
|
|
|
|
|
#include <qmltimeline.h>
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
#include <optional>
|
2015-09-18 15:38:15 +02:00
|
|
|
|
|
|
|
|
namespace QmlDesigner {
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
DynamicPropertiesModel::DynamicPropertiesModel(bool exSelection, AbstractView *parent)
|
|
|
|
|
: QStandardItemModel(parent)
|
|
|
|
|
, m_view(parent)
|
|
|
|
|
, m_delegate(new DynamicPropertiesModelBackendDelegate(this))
|
|
|
|
|
, m_explicitSelection(exSelection)
|
2022-09-09 16:33:23 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
setHorizontalHeaderLabels(DynamicPropertiesItem::headerLabels());
|
2022-09-09 16:33:23 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
AbstractView *DynamicPropertiesModel::view() const
|
2023-07-04 19:57:59 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
return m_view;
|
2023-07-04 19:57:59 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
DynamicPropertiesModelBackendDelegate *DynamicPropertiesModel::delegate() const
|
2023-07-04 19:57:59 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
return m_delegate;
|
2023-07-04 19:57:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int DynamicPropertiesModel::currentIndex() const
|
|
|
|
|
{
|
|
|
|
|
return m_currentIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
AbstractProperty DynamicPropertiesModel::currentProperty() const
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
return propertyForRow(m_currentIndex);
|
2016-05-18 20:54:02 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::add()
|
2016-05-18 20:54:02 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_PROPERTY_ADDED);
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (const QList<ModelNode> nodes = selectedNodes(); nodes.size() == 1) {
|
|
|
|
|
const ModelNode modelNode = nodes.constFirst();
|
|
|
|
|
if (!modelNode.isValid())
|
|
|
|
|
return;
|
2020-06-02 14:17:33 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
try {
|
|
|
|
|
PropertyName newName = uniquePropertyName("property", modelNode);
|
|
|
|
|
VariantProperty newProperty = modelNode.variantProperty(newName);
|
|
|
|
|
newProperty.setDynamicTypeNameAndValue("string", "This is a string");
|
|
|
|
|
} catch (RewritingException &e) {
|
|
|
|
|
showErrorMessage(e.description());
|
2020-06-02 14:17:33 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2023-08-23 12:12:07 +02:00
|
|
|
qWarning() << "DynamicPropertiesModel::add not one node selected";
|
2020-06-02 14:17:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::remove(int row)
|
2020-06-02 14:17:33 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
m_view->executeInTransaction(__FUNCTION__, [this, row]() {
|
|
|
|
|
if (DynamicPropertiesItem *item = itemForRow(row)) {
|
|
|
|
|
PropertyName name = item->propertyName();
|
|
|
|
|
if (ModelNode node = modelNodeForItem(item); node.isValid()) {
|
|
|
|
|
node.removeProperty(name);
|
|
|
|
|
|
|
|
|
|
QmlObjectNode objectNode = QmlObjectNode(node);
|
|
|
|
|
const auto stateOperations = objectNode.allAffectingStatesOperations();
|
|
|
|
|
for (const QmlModelStateOperation &stateOperation : stateOperations) {
|
|
|
|
|
if (stateOperation.modelNode().hasProperty(name))
|
|
|
|
|
stateOperation.modelNode().removeProperty(name);
|
|
|
|
|
}
|
|
|
|
|
for (auto &timelineNode : objectNode.allTimelines()) {
|
|
|
|
|
QmlTimeline timeline(timelineNode);
|
|
|
|
|
timeline.removeKeyframesForTargetAndProperty(node, name);
|
2020-06-02 14:17:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-23 12:12:07 +02:00
|
|
|
});
|
|
|
|
|
reset();
|
2022-09-09 16:33:23 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::reset(const QList<ModelNode> &modelNodes)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
AbstractProperty current = currentProperty();
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
clear();
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!modelNodes.isEmpty()) {
|
|
|
|
|
for (const ModelNode &modelNode : modelNodes)
|
|
|
|
|
addModelNode(modelNode);
|
2015-09-18 15:38:15 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (m_view->isAttached()) {
|
|
|
|
|
const QList<ModelNode> selected = selectedNodes();
|
|
|
|
|
for (const ModelNode &modelNode : selected)
|
|
|
|
|
addModelNode(modelNode);
|
2022-09-09 16:33:23 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
setCurrentProperty(current);
|
2022-09-09 16:33:23 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::setCurrentIndex(int i)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (m_currentIndex != i) {
|
|
|
|
|
m_currentIndex = i;
|
|
|
|
|
emit currentIndexChanged();
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
2023-08-23 12:12:07 +02:00
|
|
|
// Property properties may have changed.
|
|
|
|
|
m_delegate->update(currentProperty());
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::setCurrentProperty(const AbstractProperty &property)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!property.isValid())
|
2015-09-18 15:38:15 +02:00
|
|
|
return;
|
2023-03-16 16:26:36 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (auto index = findRow(property.parentModelNode().internalId(), property.name()))
|
|
|
|
|
setCurrentIndex(*index);
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::setCurrent(int internalId, const PropertyName &name)
|
2022-07-22 16:46:48 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (internalId < 0)
|
2022-07-22 16:46:48 +02:00
|
|
|
return;
|
2023-03-16 16:26:36 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (auto index = findRow(internalId, name))
|
|
|
|
|
setCurrentIndex(*index);
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::updateItem(const AbstractProperty &property)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!property.isDynamic())
|
2023-01-26 17:14:10 +01:00
|
|
|
return;
|
2022-07-22 16:46:48 +02:00
|
|
|
|
2023-09-15 14:16:20 +02:00
|
|
|
if (auto *item = itemForProperty(property)) {
|
2023-08-23 12:12:07 +02:00
|
|
|
item->updateProperty(property);
|
2023-09-15 14:16:20 +02:00
|
|
|
} else {
|
|
|
|
|
ModelNode node = property.parentModelNode();
|
|
|
|
|
if (selectedNodes().contains(node)) {
|
|
|
|
|
addProperty(property);
|
|
|
|
|
setCurrentProperty(property);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-02 14:17:33 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::removeItem(const AbstractProperty &property)
|
2020-06-02 14:17:33 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!property.isValid())
|
|
|
|
|
return;
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
AbstractProperty current = currentProperty();
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (auto index = findRow(property.parentModelNode().internalId(), property.name()))
|
|
|
|
|
static_cast<void>(removeRow(*index));
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
setCurrentProperty(current);
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
QHash<int, QByteArray> DynamicPropertiesModel::roleNames() const
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
return DynamicPropertiesItem::roleNames();
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
AbstractProperty DynamicPropertiesModel::propertyForRow(int row) const
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!m_view)
|
|
|
|
|
return {};
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!m_view->isAttached())
|
|
|
|
|
return {};
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (auto *item = itemForRow(row)) {
|
|
|
|
|
int internalId = item->internalId();
|
|
|
|
|
if (ModelNode node = m_view->modelNodeForInternalId(internalId); node.isValid())
|
|
|
|
|
return node.property(item->propertyName());
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
2023-03-16 16:26:36 +02:00
|
|
|
return {};
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
std::optional<int> DynamicPropertiesModel::findRow(int nodeId, const PropertyName &name) const
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
for (int i = 0; i < rowCount(); ++i) {
|
|
|
|
|
if (auto *item = itemForRow(i)) {
|
|
|
|
|
if (item->propertyName() == name && item->internalId() == nodeId)
|
|
|
|
|
return i;
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-23 12:12:07 +02:00
|
|
|
return std::nullopt;
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
DynamicPropertiesItem *DynamicPropertiesModel::itemForRow(int row) const
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (QModelIndex idx = index(row, 0); idx.isValid())
|
|
|
|
|
return dynamic_cast<DynamicPropertiesItem *>(itemFromIndex(idx));
|
|
|
|
|
return nullptr;
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
DynamicPropertiesItem *DynamicPropertiesModel::itemForProperty(const AbstractProperty &property) const
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!property.isValid())
|
|
|
|
|
return nullptr;
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (auto row = findRow(property.parentModelNode().internalId(), property.name()))
|
|
|
|
|
return itemForRow(*row);
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
return nullptr;
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
ModelNode DynamicPropertiesModel::modelNodeForItem(DynamicPropertiesItem *item)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!m_view->isAttached())
|
|
|
|
|
return {};
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
return m_view->modelNodeForInternalId(item->internalId());
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::addModelNode(const ModelNode &node)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!node.isValid())
|
|
|
|
|
return;
|
2022-09-09 16:33:23 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
for (const AbstractProperty &property : dynamicPropertiesFromNode(node))
|
|
|
|
|
addProperty(property);
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::addProperty(const AbstractProperty &property)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
const PropertyName name = property.name();
|
|
|
|
|
for (int i = 0; i < rowCount(); ++i) {
|
|
|
|
|
if (auto *item = itemForRow(i)) {
|
|
|
|
|
if (item->propertyName() > name) {
|
|
|
|
|
insertRow(i, new DynamicPropertiesItem(property));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
2023-08-23 12:12:07 +02:00
|
|
|
appendRow(new DynamicPropertiesItem(property));
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::commitPropertyType(int row, const TypeName &type)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
AbstractProperty property = propertyForRow(row);
|
|
|
|
|
if (!property.isValid())
|
2022-09-06 09:57:20 +03:00
|
|
|
return;
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
ModelNode node = property.parentModelNode();
|
|
|
|
|
RewriterTransaction transaction = m_view->beginRewriterTransaction(__FUNCTION__);
|
|
|
|
|
try {
|
|
|
|
|
if (property.isBindingProperty()) {
|
|
|
|
|
BindingProperty binding = property.toBindingProperty();
|
|
|
|
|
const QString expression = binding.expression();
|
|
|
|
|
binding.parentModelNode().removeProperty(binding.name());
|
|
|
|
|
binding.setDynamicTypeNameAndExpression(type, expression);
|
|
|
|
|
} else if (property.isVariantProperty()) {
|
|
|
|
|
VariantProperty variant = property.toVariantProperty();
|
|
|
|
|
QVariant val = typeConvertVariant(variant.value(), type);
|
|
|
|
|
variant.parentModelNode().removeProperty(variant.name());
|
|
|
|
|
variant.setDynamicTypeNameAndValue(type, val);
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
2023-08-23 12:12:07 +02:00
|
|
|
transaction.commit();
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
} catch (Exception &e) {
|
|
|
|
|
showErrorMessage(e.description());
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::commitPropertyName(int row, const PropertyName &name)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
AbstractProperty property = propertyForRow(row);
|
|
|
|
|
if (!property.isValid())
|
2015-09-18 15:38:15 +02:00
|
|
|
return;
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
ModelNode node = property.parentModelNode();
|
|
|
|
|
if (property.isBindingProperty()) {
|
|
|
|
|
BindingProperty binding = property.toBindingProperty();
|
|
|
|
|
m_view->executeInTransaction(__FUNCTION__, [binding, name, &node]() {
|
|
|
|
|
const QString expression = binding.expression();
|
|
|
|
|
const TypeName type = binding.dynamicTypeName();
|
|
|
|
|
node.removeProperty(binding.name());
|
|
|
|
|
node.bindingProperty(name).setDynamicTypeNameAndExpression(type, expression);
|
2019-05-31 16:49:04 +02:00
|
|
|
});
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
} else if (property.isVariantProperty()) {
|
|
|
|
|
VariantProperty variant = property.toVariantProperty();
|
|
|
|
|
m_view->executeInTransaction(__FUNCTION__, [variant, name, &node]() {
|
|
|
|
|
const QVariant value = variant.value();
|
|
|
|
|
const TypeName type = variant.dynamicTypeName();
|
|
|
|
|
node.removeProperty(variant.name());
|
|
|
|
|
node.variantProperty(name).setDynamicTypeNameAndValue(type, value);
|
|
|
|
|
});
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::commitPropertyValue(int row, const QVariant &value)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
AbstractProperty property = propertyForRow(row);
|
|
|
|
|
if (!property.isValid())
|
2015-09-18 15:38:15 +02:00
|
|
|
return;
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
RewriterTransaction transaction = m_view->beginRewriterTransaction(__FUNCTION__);
|
|
|
|
|
try {
|
|
|
|
|
bool isBindingValue = isBindingExpression(value);
|
|
|
|
|
if (property.isBindingProperty()) {
|
|
|
|
|
BindingProperty binding = property.toBindingProperty();
|
|
|
|
|
if (!isBindingValue) {
|
|
|
|
|
convertBindingToVariantProperty(binding, value);
|
2015-09-18 15:38:15 +02:00
|
|
|
} else {
|
2023-08-23 12:12:07 +02:00
|
|
|
const QString expression = value.toString();
|
|
|
|
|
const TypeName typeName = binding.dynamicTypeName();
|
|
|
|
|
binding.setDynamicTypeNameAndExpression(typeName, expression);
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
2023-08-23 12:12:07 +02:00
|
|
|
} else if (property.isVariantProperty()) {
|
|
|
|
|
VariantProperty variant = property.toVariantProperty();
|
|
|
|
|
if (isBindingValue)
|
|
|
|
|
convertVariantToBindingProperty(variant, value);
|
|
|
|
|
else
|
|
|
|
|
variant.setDynamicTypeNameAndValue(variant.dynamicTypeName(), value);
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
2023-08-23 12:12:07 +02:00
|
|
|
transaction.commit();
|
|
|
|
|
} catch (Exception &e) {
|
|
|
|
|
showErrorMessage(e.description());
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::dispatchPropertyChanges(const AbstractProperty &abstractProperty)
|
2015-09-18 15:38:15 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (abstractProperty.parentModelNode().simplifiedTypeName() == "PropertyChanges") {
|
|
|
|
|
QmlPropertyChanges changes(abstractProperty.parentModelNode());
|
|
|
|
|
if (changes.target().isValid()) {
|
|
|
|
|
const ModelNode target = changes.target();
|
|
|
|
|
const PropertyName propertyName = abstractProperty.name();
|
|
|
|
|
const AbstractProperty targetProperty = target.variantProperty(propertyName);
|
|
|
|
|
if (target.hasProperty(propertyName) && targetProperty.isDynamic())
|
|
|
|
|
updateItem(targetProperty);
|
|
|
|
|
}
|
2015-09-18 15:38:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-22 16:46:48 +02:00
|
|
|
const QList<ModelNode> DynamicPropertiesModel::selectedNodes() const
|
|
|
|
|
{
|
|
|
|
|
if (m_explicitSelection)
|
|
|
|
|
return m_selectedNodes;
|
2023-03-16 16:26:36 +02:00
|
|
|
|
|
|
|
|
return m_view->selectedModelNodes();
|
2022-07-22 16:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ModelNode DynamicPropertiesModel::singleSelectedNode() const
|
|
|
|
|
{
|
|
|
|
|
if (m_explicitSelection)
|
|
|
|
|
return m_selectedNodes.first();
|
|
|
|
|
|
2023-03-16 16:26:36 +02:00
|
|
|
return m_view->singleSelectedModelNode();
|
|
|
|
|
}
|
2015-09-18 15:38:15 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModel::setSelectedNode(const ModelNode &node)
|
2023-07-04 19:57:59 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
QTC_ASSERT(m_explicitSelection, return);
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!node.isValid())
|
|
|
|
|
return;
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
m_selectedNodes.clear();
|
|
|
|
|
m_selectedNodes.append(node);
|
|
|
|
|
reset();
|
2023-07-04 19:57:59 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
DynamicPropertiesModelBackendDelegate::DynamicPropertiesModelBackendDelegate(DynamicPropertiesModel *parent)
|
2023-07-04 19:57:59 +02:00
|
|
|
: QObject(parent)
|
2023-08-23 12:12:07 +02:00
|
|
|
, m_internalNodeId(std::nullopt)
|
2023-07-04 19:57:59 +02:00
|
|
|
{
|
|
|
|
|
m_type.setModel({"int", "bool", "var", "real", "string", "url", "color"});
|
|
|
|
|
connect(&m_type, &StudioQmlComboBoxBackend::activated, this, [this]() { handleTypeChanged(); });
|
|
|
|
|
connect(&m_name, &StudioQmlTextBackend::activated, this, [this]() { handleNameChanged(); });
|
|
|
|
|
connect(&m_value, &StudioQmlTextBackend::activated, this, [this]() { handleValueChanged(); });
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModelBackendDelegate::update(const AbstractProperty &property)
|
2023-07-04 19:57:59 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (!property.isValid())
|
2023-07-04 19:57:59 +02:00
|
|
|
return;
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
m_internalNodeId = property.parentModelNode().internalId();
|
2023-07-04 19:57:59 +02:00
|
|
|
m_type.setCurrentText(QString::fromUtf8(property.dynamicTypeName()));
|
|
|
|
|
m_name.setText(QString::fromUtf8(property.name()));
|
|
|
|
|
|
|
|
|
|
if (property.isVariantProperty())
|
|
|
|
|
m_value.setText(property.toVariantProperty().value().toString());
|
|
|
|
|
else if (property.isBindingProperty())
|
|
|
|
|
m_value.setText(property.toBindingProperty().expression());
|
2023-09-01 17:29:07 +02:00
|
|
|
|
|
|
|
|
m_targetNode = property.parentModelNode().id();
|
|
|
|
|
emit targetNodeChanged();
|
2023-07-04 19:57:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DynamicPropertiesModelBackendDelegate::handleTypeChanged()
|
|
|
|
|
{
|
|
|
|
|
DynamicPropertiesModel *model = qobject_cast<DynamicPropertiesModel *>(parent());
|
2023-08-23 12:12:07 +02:00
|
|
|
QTC_ASSERT(model, return);
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
const PropertyName name = m_name.text().toUtf8();
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
int current = model->currentIndex();
|
|
|
|
|
const TypeName type = m_type.currentText().toUtf8();
|
|
|
|
|
model->commitPropertyType(current, type);
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
// The order might have changed!
|
|
|
|
|
model->setCurrent(m_internalNodeId.value_or(-1), name);
|
2023-07-04 19:57:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DynamicPropertiesModelBackendDelegate::handleNameChanged()
|
|
|
|
|
{
|
|
|
|
|
DynamicPropertiesModel *model = qobject_cast<DynamicPropertiesModel *>(parent());
|
2023-08-23 12:12:07 +02:00
|
|
|
QTC_ASSERT(model, return);
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
const PropertyName name = m_name.text().toUtf8();
|
|
|
|
|
QTC_ASSERT(!name.isEmpty(), return);
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
int current = model->currentIndex();
|
|
|
|
|
model->commitPropertyName(current, name);
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
// The order might have changed!
|
|
|
|
|
model->setCurrent(m_internalNodeId.value_or(-1), name);
|
2023-07-04 19:57:59 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
// TODO: Maybe replace with utils typeConvertVariant?
|
|
|
|
|
QVariant valueFromText(const QString &value, const QString &type)
|
2023-07-04 19:57:59 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
if (isBindingExpression(value))
|
|
|
|
|
return value;
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (type == "real" || type == "int")
|
|
|
|
|
return value.toFloat();
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
if (type == "bool")
|
|
|
|
|
return value == "true";
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
return value;
|
2023-07-04 19:57:59 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
void DynamicPropertiesModelBackendDelegate::handleValueChanged()
|
2023-07-04 19:57:59 +02:00
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
DynamicPropertiesModel *model = qobject_cast<DynamicPropertiesModel *>(parent());
|
|
|
|
|
QTC_ASSERT(model, return);
|
2023-07-04 19:57:59 +02:00
|
|
|
|
2023-08-23 12:12:07 +02:00
|
|
|
int current = model->currentIndex();
|
|
|
|
|
QVariant value = valueFromText(m_value.text(), m_type.currentText());
|
|
|
|
|
model->commitPropertyValue(current, value);
|
2023-07-04 19:57:59 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-01 17:29:07 +02:00
|
|
|
QString DynamicPropertiesModelBackendDelegate::targetNode() const
|
|
|
|
|
{
|
|
|
|
|
return m_targetNode;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-04 19:57:59 +02:00
|
|
|
StudioQmlComboBoxBackend *DynamicPropertiesModelBackendDelegate::type()
|
|
|
|
|
{
|
|
|
|
|
return &m_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StudioQmlTextBackend *DynamicPropertiesModelBackendDelegate::name()
|
|
|
|
|
{
|
|
|
|
|
return &m_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StudioQmlTextBackend *DynamicPropertiesModelBackendDelegate::value()
|
|
|
|
|
{
|
|
|
|
|
return &m_value;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 15:38:15 +02:00
|
|
|
} // namespace QmlDesigner
|