canStartConnection method
Validates whether a connection can start from the specified port.
This method checks:
- Port exists and is connectable
- Direction compatibility (output can emit, input can receive)
- Max connections not exceeded (for source ports)
- Custom validation via ConnectionEvents.onBeforeStart callback
Returns a ConnectionValidationResult indicating if the connection can start.
Implementation
ConnectionValidationResult canStartConnection({
required String nodeId,
required String portId,
required bool isOutput,
}) {
final node = _nodes[nodeId];
if (node == null) {
return const ConnectionValidationResult.deny(reason: 'Node not found');
}
final port = node.allPorts.where((p) => p.id == portId).firstOrNull;
if (port == null) {
return const ConnectionValidationResult.deny(reason: 'Port not found');
}
// Port must be connectable
if (!port.isConnectable) {
return const ConnectionValidationResult.deny(
reason: 'Port is not connectable',
);
}
// Direction check: output ports must be able to emit
// input ports must be able to receive
if (isOutput && !port.isOutput) {
return const ConnectionValidationResult.deny(
reason: 'Port cannot emit connections',
);
}
if (!isOutput && !port.isInput) {
return const ConnectionValidationResult.deny(
reason: 'Port cannot receive connections',
);
}
// Get existing connections for this port
final existingConnections = _connections
.where(
(conn) => isOutput
? (conn.sourceNodeId == nodeId && conn.sourcePortId == portId)
: (conn.targetNodeId == nodeId && conn.targetPortId == portId),
)
.map((c) => c.id)
.toList();
// Check max connections for source port (output side)
// Note: For input ports starting a drag, they become the target,
// so we check source (output) max connections
if (isOutput && port.maxConnections != null) {
// If port doesn't allow multi-connections, we'll remove existing on drag
// So only block if multi-connections is allowed but max is reached
if (port.multiConnections &&
existingConnections.length >= port.maxConnections!) {
return const ConnectionValidationResult.deny(
reason: 'Maximum connections reached',
);
}
}
// Call custom validation callback if provided
final onBeforeStart = events.connection?.onBeforeStart;
if (onBeforeStart != null) {
final context = ConnectionStartContext<T>(
sourceNode: node,
sourcePort: port,
existingConnections: existingConnections,
);
final result = onBeforeStart(context);
if (!result.allowed) {
return result;
}
}
return const ConnectionValidationResult.allow();
}