QmlDesigner: Extend Connections view support

- Connection view support to components
 - Connection view support to singletons
 - Minor reparenting improvements
Task: QDS-2411

Change-Id: I337535012dbb3d3a1722d75d89156463eabb8a4c
Reviewed-by: Vikas Pachdha <vikas.pachdha@qt.io>
This commit is contained in:
Aleksei German
2020-07-15 15:47:13 +02:00
committed by Thomas Hartmann
parent 3e1d204c32
commit 66122492a6
4 changed files with 135 additions and 40 deletions

View File

@@ -221,6 +221,13 @@ void ConnectionModel::updateTargetNode(int rowNumber)
isSingleton = true; isSingleton = true;
break; break;
} }
} else if (isAlias) {
if (data.typeName == newTarget.split(".").constFirst()) {
if (connectionView()->model()->metaInfo(data.typeName.toUtf8()).isValid()) {
isSingleton = true;
break;
}
}
} }
} }
} }
@@ -229,7 +236,7 @@ void ConnectionModel::updateTargetNode(int rowNumber)
if (!newTarget.isEmpty()) { if (!newTarget.isEmpty()) {
//if it's a singleton, then let's reparent connections to rootNode, //if it's a singleton, then let's reparent connections to rootNode,
//if it's an alias, then reparent to alias property owner: //if it's an alias, then reparent to alias property owner:
const ModelNode parent = connectionView()->modelNodeForId(isSingleton const ModelNode parent = connectionView()->modelNodeForId((isSingleton || (isSingleton && isAlias))
? connectionView()->rootModelNode().id() ? connectionView()->rootModelNode().id()
: isAlias : isAlias
? newTarget.split(".").constFirst() ? newTarget.split(".").constFirst()
@@ -255,35 +262,36 @@ void ConnectionModel::updateCustomData(QStandardItem *item, const SignalHandlerP
ModelNode ConnectionModel::getTargetNodeForConnection(const ModelNode &connection) const ModelNode ConnectionModel::getTargetNodeForConnection(const ModelNode &connection) const
{ {
BindingProperty bindingProperty = connection.bindingProperty("target"); ModelNode result;
const BindingProperty bindingProperty = connection.bindingProperty("target");
const QString bindExpression = bindingProperty.expression();
if (bindingProperty.isValid()) { if (bindingProperty.isValid()) {
bool isAlias = bindingProperty.expression().contains("."); if (bindExpression == QLatin1String("parent")) {
result = connection.parentProperty().parentModelNode();
if (bindingProperty.expression() == QLatin1String("parent")) } else if (bindExpression.contains(".")) {
return connection.parentProperty().parentModelNode(); QStringList substr = bindExpression.split(".");
else if (isAlias) { const QString itemId = substr.constFirst();
QStringList substr = bindingProperty.expression().split(".");
if (substr.size() > 1) { if (substr.size() > 1) {
ModelNode aliasParent = connectionView()->modelNodeForId(substr.constFirst()); const ModelNode aliasParent = (itemId == QLatin1String("parent")
QString aliasBody = substr.at(1); ? connection.parentProperty().parentModelNode()
if (aliasParent.hasProperty(aliasBody.toUtf8())) { : connectionView()->modelNodeForId(itemId));
AbstractProperty abstractProp = aliasParent.property(aliasBody.toUtf8()); substr.removeFirst(); //remove id, only alias pieces left
if (abstractProp.isBindingProperty()) { const QString aliasBody = substr.join(".");
BindingProperty binding = abstractProp.toBindingProperty(); if (aliasParent.isValid() && aliasParent.hasBindingProperty(aliasBody.toUtf8())) {
if (connectionView()->hasId(binding.expression())) { const BindingProperty binding = aliasParent.bindingProperty(aliasBody.toUtf8());
ModelNode resolve = connectionView()->modelNodeForId(binding.expression()); if (binding.isValid() && connectionView()->hasId(binding.expression())) {
if (resolve.isValid()) result = connectionView()->modelNodeForId(binding.expression());
return resolve;
}
} }
} }
} }
} else {
result = connectionView()->modelNodeForId(bindExpression);
} }
return connectionView()->modelNodeForId(bindingProperty.expression());
} }
return ModelNode(); return result;
} }
void ConnectionModel::addConnection() void ConnectionModel::addConnection()
@@ -355,8 +363,7 @@ void ConnectionModel::deleteConnectionByRow(int currentRow)
if (allSignals.size() > 1) { if (allSignals.size() > 1) {
if (allSignals.contains(targetSignal)) if (allSignals.contains(targetSignal))
node.removeProperty(targetSignal.name()); node.removeProperty(targetSignal.name());
} } else {
else {
node.destroy(); node.destroy();
} }
} }
@@ -448,21 +455,44 @@ QStringList ConnectionModel::getPossibleSignalsForConnection(const ModelNode &co
{ {
QStringList stringList; QStringList stringList;
if (connection.isValid()) { auto getAliasMetaSignals = [&](QString aliasPart, NodeMetaInfo metaInfo) {
if (metaInfo.isValid() && metaInfo.hasProperty(aliasPart.toUtf8())) {
NodeMetaInfo propertyMetaInfo = connectionView()->model()->metaInfo(
metaInfo.propertyTypeName(aliasPart.toUtf8()));
if (propertyMetaInfo.isValid()) {
return propertyNameListToStringList(propertyMetaInfo.signalNames());
}
}
return QStringList();
};
if (connection.isValid()) {
//separate check for singletons //separate check for singletons
if (connection.hasBindingProperty("target")) { if (connection.hasBindingProperty("target")) {
BindingProperty bp = connection.bindingProperty("target"); const BindingProperty bp = connection.bindingProperty("target");
if (bp.isValid()) { if (bp.isValid()) {
if (RewriterView *rv = connectionView()->rewriterView()) { const QString bindExpression = bp.expression();
if (const RewriterView * const rv = connectionView()->rewriterView()) {
for (const QmlTypeData &data : rv->getQMLTypes()) { for (const QmlTypeData &data : rv->getQMLTypes()) {
if (!data.typeName.isEmpty()) { if (!data.typeName.isEmpty()) {
if (data.typeName == bp.expression()) { if (data.typeName == bindExpression) {
NodeMetaInfo metaInfo = connectionView()->model()->metaInfo(data.typeName.toUtf8()); NodeMetaInfo metaInfo = connectionView()->model()->metaInfo(data.typeName.toUtf8());
if (metaInfo.isValid()) { if (metaInfo.isValid()) {
stringList.append(propertyNameListToStringList(metaInfo.signalNames())); stringList << propertyNameListToStringList(metaInfo.signalNames());
return stringList; break;
}
} else if (bindExpression.contains(".")) {
//if it doesn't fit the same name, maybe it's an alias?
QStringList expression = bindExpression.split(".");
if ((expression.size() > 1) && (expression.constFirst() == data.typeName)) {
expression.removeFirst();
stringList << getAliasMetaSignals(
expression.join("."),
connectionView()->model()->metaInfo(data.typeName.toUtf8()));
break;
} }
} }
} }
@@ -474,6 +504,30 @@ QStringList ConnectionModel::getPossibleSignalsForConnection(const ModelNode &co
ModelNode targetNode = getTargetNodeForConnection(connection); ModelNode targetNode = getTargetNodeForConnection(connection);
if (targetNode.isValid() && targetNode.metaInfo().isValid()) { if (targetNode.isValid() && targetNode.metaInfo().isValid()) {
stringList.append(propertyNameListToStringList(targetNode.metaInfo().signalNames())); stringList.append(propertyNameListToStringList(targetNode.metaInfo().signalNames()));
} else {
//most likely it's component's internal alias:
if (connection.hasBindingProperty("target")) {
const BindingProperty bp = connection.bindingProperty("target");
if (bp.isValid()) {
const QString bindExpression = bp.expression();
QStringList expression = bp.expression().split(".");
if (expression.size() > 1) {
const QString itemId = expression.constFirst();
if (connectionView()->hasId(itemId)) {
ModelNode parentItem = connectionView()->modelNodeForId(itemId);
if (parentItem.isValid()
&& parentItem.hasMetaInfo()
&& parentItem.metaInfo().isValid()) {
expression.removeFirst();
stringList << getAliasMetaSignals(expression.join("."),
parentItem.metaInfo());
}
}
}
}
}
} }
} }

View File

@@ -295,6 +295,35 @@ QWidget *ConnectionDelegate::createEditor(QWidget *parent, const QStyleOptionVie
switch (index.column()) { switch (index.column()) {
case ConnectionModel::TargetModelNodeRow: { case ConnectionModel::TargetModelNodeRow: {
auto addMetaInfoProperties = [&](const NodeMetaInfo& itemMetaInfo, QString itemName){
if (itemMetaInfo.isValid()) {
for (const PropertyName &propertyName : itemMetaInfo.directPropertyNames()) {
TypeName propertyType = itemMetaInfo.propertyTypeName(propertyName);
if (!propertyType.isEmpty()) {
//first letter is a reliable item indicator
QChar firstLetter = QString::fromUtf8(propertyType).at(0);
if (firstLetter.isLetter() && firstLetter.isUpper()) {
if (!itemMetaInfo.propertyIsEnumType(propertyName)
&& !itemMetaInfo.propertyIsPrivate(propertyName)
&& !itemMetaInfo.propertyIsListProperty(propertyName)
&& !itemMetaInfo.propertyIsPointer(propertyName)) {
NodeMetaInfo propertyMetaInfo =
connectionModel->connectionView()->model()->metaInfo(propertyType);
if (propertyMetaInfo.isValid()) {
if (propertyMetaInfo.isQmlItem()) {
connectionComboBox->addItem(itemName
+ "."
+ propertyName);
}
}
}
}
}
}
}
};
for (const ModelNode &modelNode : connectionModel->connectionView()->allModelNodes()) { for (const ModelNode &modelNode : connectionModel->connectionView()->allModelNodes()) {
if (!modelNode.id().isEmpty()) { if (!modelNode.id().isEmpty()) {
connectionComboBox->addItem(modelNode.id()); connectionComboBox->addItem(modelNode.id());
@@ -308,25 +337,24 @@ QWidget *ConnectionDelegate::createEditor(QWidget *parent, const QStyleOptionVie
} }
} }
} }
//Components
if (modelNode.isComponent()) {
NodeMetaInfo componentMetaInfo = modelNode.metaInfo();
addMetaInfoProperties(componentMetaInfo, modelNode.id());
}
} }
} }
//singletons: //singletons:
if (RewriterView* rv = connectionModel->connectionView()->rewriterView()) { if (RewriterView* rv = connectionModel->connectionView()->rewriterView()) {
for (const QmlTypeData &data : rv->getQMLTypes()) { for (const QmlTypeData &data : rv->getQMLTypes()) {
if (!data.typeName.isEmpty()) { if (!data.typeName.isEmpty()) {
//singleton itself
connectionComboBox->addItem(data.typeName); connectionComboBox->addItem(data.typeName);
//its properties, mostly looking for aliases:
NodeMetaInfo metaInfo = connectionModel->connectionView()->model()->metaInfo(data.typeName.toUtf8()); NodeMetaInfo metaInfo = connectionModel->connectionView()->model()->metaInfo(data.typeName.toUtf8());
addMetaInfoProperties(metaInfo, data.typeName);
if (metaInfo.isValid()) {
for (const PropertyName &propertyName : metaInfo.propertyNames()) {
if (metaInfo.propertyTypeName(propertyName) == "alias") {
connectionComboBox->addItem(data.typeName
+ "."
+ QString::fromUtf8(propertyName));
}
}
}
} }
} }
} }

View File

@@ -75,6 +75,7 @@ public:
bool propertyIsListProperty(const PropertyName &propertyName) const; bool propertyIsListProperty(const PropertyName &propertyName) const;
bool propertyIsEnumType(const PropertyName &propertyName) const; bool propertyIsEnumType(const PropertyName &propertyName) const;
bool propertyIsPrivate(const PropertyName &propertyName) const; bool propertyIsPrivate(const PropertyName &propertyName) const;
bool propertyIsPointer(const PropertyName &propertyName) const;
QString propertyEnumScope(const PropertyName &propertyName) const; QString propertyEnumScope(const PropertyName &propertyName) const;
QStringList propertyKeysForEnum(const PropertyName &propertyName) const; QStringList propertyKeysForEnum(const PropertyName &propertyName) const;
QVariant propertyCastedValue(const PropertyName &propertyName, const QVariant &value) const; QVariant propertyCastedValue(const PropertyName &propertyName, const QVariant &value) const;
@@ -99,6 +100,7 @@ public:
bool isSubclassOf(const TypeName &type, int majorVersion = -1, int minorVersion = -1) const; bool isSubclassOf(const TypeName &type, int majorVersion = -1, int minorVersion = -1) const;
bool isGraphicalItem() const; bool isGraphicalItem() const;
bool isQmlItem() const;
bool isLayoutable() const; bool isLayoutable() const;
bool isView() const; bool isView() const;
bool isTabView() const; bool isTabView() const;

View File

@@ -427,7 +427,7 @@ QVector<PropertyInfo> getQmlTypes(const CppComponentValue *objectValue, const Co
PropertyMemberProcessor processor(context); PropertyMemberProcessor processor(context);
objectValue->processMembers(&processor); objectValue->processMembers(&processor);
foreach (const PropertyInfo &property, processor.properties()) { for (const PropertyInfo &property : processor.properties()) {
const PropertyName name = property.first; const PropertyName name = property.first;
const QString nameAsString = QString::fromUtf8(name); const QString nameAsString = QString::fromUtf8(name);
if (!objectValue->isWritable(nameAsString) && objectValue->isPointer(nameAsString)) { if (!objectValue->isWritable(nameAsString) && objectValue->isPointer(nameAsString)) {
@@ -1500,6 +1500,11 @@ bool NodeMetaInfo::propertyIsPrivate(const PropertyName &propertyName) const
return propertyName.startsWith("__"); return propertyName.startsWith("__");
} }
bool NodeMetaInfo::propertyIsPointer(const PropertyName &propertyName) const
{
return m_privateData->isPropertyPointer(propertyName);
}
QString NodeMetaInfo::propertyEnumScope(const PropertyName &propertyName) const QString NodeMetaInfo::propertyEnumScope(const PropertyName &propertyName) const
{ {
return m_privateData->propertyEnumScope(propertyName); return m_privateData->propertyEnumScope(propertyName);
@@ -1660,6 +1665,12 @@ bool NodeMetaInfo::isGraphicalItem() const
|| isSubclassOf("QtQuick.Controls.Popup"); || isSubclassOf("QtQuick.Controls.Popup");
} }
bool NodeMetaInfo::isQmlItem() const
{
return isSubclassOf("QtQuick.QtObject")
|| isSubclassOf("QtQml.QtObject");
}
void NodeMetaInfo::clearCache() void NodeMetaInfo::clearCache()
{ {
Internal::NodeMetaInfoPrivate::clearCache(); Internal::NodeMetaInfoPrivate::clearCache();