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;
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 it's a singleton, then let's reparent connections to rootNode,
//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()
: isAlias
? newTarget.split(".").constFirst()
@@ -255,35 +262,36 @@ void ConnectionModel::updateCustomData(QStandardItem *item, const SignalHandlerP
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()) {
bool isAlias = bindingProperty.expression().contains(".");
if (bindingProperty.expression() == QLatin1String("parent"))
return connection.parentProperty().parentModelNode();
else if (isAlias) {
QStringList substr = bindingProperty.expression().split(".");
if (bindExpression == QLatin1String("parent")) {
result = connection.parentProperty().parentModelNode();
} else if (bindExpression.contains(".")) {
QStringList substr = bindExpression.split(".");
const QString itemId = substr.constFirst();
if (substr.size() > 1) {
ModelNode aliasParent = connectionView()->modelNodeForId(substr.constFirst());
QString aliasBody = substr.at(1);
if (aliasParent.hasProperty(aliasBody.toUtf8())) {
AbstractProperty abstractProp = aliasParent.property(aliasBody.toUtf8());
if (abstractProp.isBindingProperty()) {
BindingProperty binding = abstractProp.toBindingProperty();
if (connectionView()->hasId(binding.expression())) {
ModelNode resolve = connectionView()->modelNodeForId(binding.expression());
if (resolve.isValid())
return resolve;
}
const ModelNode aliasParent = (itemId == QLatin1String("parent")
? connection.parentProperty().parentModelNode()
: connectionView()->modelNodeForId(itemId));
substr.removeFirst(); //remove id, only alias pieces left
const QString aliasBody = substr.join(".");
if (aliasParent.isValid() && aliasParent.hasBindingProperty(aliasBody.toUtf8())) {
const BindingProperty binding = aliasParent.bindingProperty(aliasBody.toUtf8());
if (binding.isValid() && connectionView()->hasId(binding.expression())) {
result = connectionView()->modelNodeForId(binding.expression());
}
}
}
} else {
result = connectionView()->modelNodeForId(bindExpression);
}
return connectionView()->modelNodeForId(bindingProperty.expression());
}
return ModelNode();
return result;
}
void ConnectionModel::addConnection()
@@ -355,8 +363,7 @@ void ConnectionModel::deleteConnectionByRow(int currentRow)
if (allSignals.size() > 1) {
if (allSignals.contains(targetSignal))
node.removeProperty(targetSignal.name());
}
else {
} else {
node.destroy();
}
}
@@ -448,21 +455,44 @@ QStringList ConnectionModel::getPossibleSignalsForConnection(const ModelNode &co
{
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
if (connection.hasBindingProperty("target")) {
BindingProperty bp = connection.bindingProperty("target");
const BindingProperty bp = connection.bindingProperty("target");
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()) {
if (!data.typeName.isEmpty()) {
if (data.typeName == bp.expression()) {
if (data.typeName == bindExpression) {
NodeMetaInfo metaInfo = connectionView()->model()->metaInfo(data.typeName.toUtf8());
if (metaInfo.isValid()) {
stringList.append(propertyNameListToStringList(metaInfo.signalNames()));
return stringList;
stringList << propertyNameListToStringList(metaInfo.signalNames());
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);
if (targetNode.isValid() && targetNode.metaInfo().isValid()) {
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()) {
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()) {
if (!modelNode.id().isEmpty()) {
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:
if (RewriterView* rv = connectionModel->connectionView()->rewriterView()) {
for (const QmlTypeData &data : rv->getQMLTypes()) {
if (!data.typeName.isEmpty()) {
//singleton itself
connectionComboBox->addItem(data.typeName);
//its properties, mostly looking for aliases:
NodeMetaInfo metaInfo = connectionModel->connectionView()->model()->metaInfo(data.typeName.toUtf8());
if (metaInfo.isValid()) {
for (const PropertyName &propertyName : metaInfo.propertyNames()) {
if (metaInfo.propertyTypeName(propertyName) == "alias") {
connectionComboBox->addItem(data.typeName
+ "."
+ QString::fromUtf8(propertyName));
}
}
}
addMetaInfoProperties(metaInfo, data.typeName);
}
}
}

View File

@@ -75,6 +75,7 @@ public:
bool propertyIsListProperty(const PropertyName &propertyName) const;
bool propertyIsEnumType(const PropertyName &propertyName) const;
bool propertyIsPrivate(const PropertyName &propertyName) const;
bool propertyIsPointer(const PropertyName &propertyName) const;
QString propertyEnumScope(const PropertyName &propertyName) const;
QStringList propertyKeysForEnum(const PropertyName &propertyName) 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 isGraphicalItem() const;
bool isQmlItem() const;
bool isLayoutable() const;
bool isView() const;
bool isTabView() const;

View File

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