[ui] GraphEditor: only connect compatible attributes

This commit is contained in:
Fabien Castan 2020-12-28 15:29:10 +01:00
parent 85044e50cb
commit 5fb6a5fb0f
3 changed files with 35 additions and 18 deletions

View file

@ -93,6 +93,9 @@ class Attribute(BaseObject):
def getType(self):
return self.attributeDesc.__class__.__name__
def getBaseType(self):
return self.getType()
def getLabel(self):
return self._label
@ -258,6 +261,7 @@ class Attribute(BaseObject):
fullName = Property(str, getFullName, constant=True)
label = Property(str, getLabel, constant=True)
type = Property(str, getType, constant=True)
baseType = Property(str, getType, constant=True)
desc = Property(desc.Attribute, lambda self: self.attributeDesc, constant=True)
valueChanged = Signal()
value = Property(Variant, _get_value, _set_value, notify=valueChanged)
@ -292,6 +296,9 @@ class ListAttribute(Attribute):
def __len__(self):
return len(self._value)
def getBaseType(self):
return self.attributeDesc.elementDesc.__class__.__name__
def at(self, idx):
""" Returns child attribute at index 'idx' """
# implement 'at' rather than '__getitem__'
@ -396,6 +403,7 @@ class ListAttribute(Attribute):
# Override value property setter
value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged)
isDefault = Property(bool, _isDefault, notify=Attribute.valueChanged)
baseType = Property(str, getBaseType, constant=True)
class GroupAttribute(Attribute):

View file

@ -227,6 +227,9 @@ class AddEdgeCommand(GraphCommand):
self.dstAttr = dst.getFullName()
self.setText("Connect '{}'->'{}'".format(self.srcAttr, self.dstAttr))
if src.baseType != dst.baseType:
raise ValueError("Attribute types are not compatible and cannot be connected: '{}'({})->'{}'({})".format(self.srcAttr, src.baseType, self.dstAttr, dst.baseType))
def redoImpl(self):
self.graph.addEdge(self.graph.attribute(self.srcAttr), self.graph.attribute(self.dstAttr))
return True

View file

@ -82,16 +82,18 @@ RowLayout {
keys: [inputDragTarget.objectName]
onEntered: {
// Filter drops:
if( root.readOnly
// Check if attributes are compatible to create a valid connection
if( root.readOnly // cannot connect on a read-only attribute
|| drag.source.objectName != inputDragTarget.objectName // not an edge connector
|| drag.source.baseType != inputDragTarget.baseType // not the same base type
|| drag.source.nodeItem == inputDragTarget.nodeItem // connection between attributes of the same node
|| inputDragTarget.attribute.isLink // already connected attribute
|| (drag.source.isList && !inputDragTarget.isList) // connection between a list and a simple attribute
|| (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children
|| drag.source.connectorType == "input"
|| drag.source.connectorType == "input" // refuse to connect an "input pin" on another one (input attr can be connected to input attr, but not the graphical pin)
)
{
// Refuse attributes connection
drag.accepted = false
}
inputDropArea.acceptableDrop = drag.accepted
@ -112,7 +114,8 @@ RowLayout {
readonly property string connectorType: "input"
readonly property alias attribute: root.attribute
readonly property alias nodeItem: root.nodeItem
readonly property bool isOutput: attribute && attribute.isOutput
readonly property bool isOutput: attribute.isOutput
readonly property string baseType: attribute.baseType
readonly property alias isList: root.isList
property bool dragAccepted: false
anchors.verticalCenter: parent.verticalCenter
@ -219,15 +222,17 @@ RowLayout {
keys: [outputDragTarget.objectName]
onEntered: {
// Filter drops:
// Check if attributes are compatible to create a valid connection
if( drag.source.objectName != outputDragTarget.objectName // not an edge connector
|| drag.source.baseType != outputDragTarget.baseType // not the same base type
|| drag.source.nodeItem == outputDragTarget.nodeItem // connection between attributes of the same node
|| drag.source.attribute.isLink // already connected attribute
|| (!drag.source.isList && outputDragTarget.isList) // connection between a list and a simple attribute
|| (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children
|| drag.source.connectorType == "output"
|| drag.source.connectorType == "output" // refuse to connect an output pin on another one
)
{
// Refuse attributes connection
drag.accepted = false
}
outputDropArea.acceptableDrop = drag.accepted
@ -249,6 +254,7 @@ RowLayout {
readonly property alias nodeItem: root.nodeItem
readonly property bool isOutput: attribute.isOutput
readonly property alias isList: root.isList
readonly property string baseType: attribute.baseType
property bool dropAccepted: false
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter