public CodeBlockEditor(NodeViewModel nodeViewModel) { InitializeComponent(); this.nodeViewModel = nodeViewModel; this.dynamoViewModel = nodeViewModel.DynamoViewModel; this.DataContext = nodeViewModel.NodeModel; this.nodeModel = nodeViewModel.NodeModel as CodeBlockNodeModel; // Register text editing events this.InnerTextEditor.TextChanged += InnerTextEditor_TextChanged; this.InnerTextEditor.TextArea.LostFocus += TextArea_LostFocus; // the code block should not be in focus upon undo/redo actions on node if (this.nodeModel.ShouldFocus) { this.Loaded += (obj, args) => this.InnerTextEditor.TextArea.Focus(); } // Register auto-completion callbacks this.InnerTextEditor.TextArea.TextEntering += OnTextAreaTextEntering; this.InnerTextEditor.TextArea.TextEntered += OnTextAreaTextEntered; InitializeSyntaxHighlighter(); }
public CodeBlockEditor(NodeView nodeView): this() { this.nodeViewModel = nodeView.ViewModel; this.dynamoViewModel = nodeViewModel.DynamoViewModel; this.DataContext = nodeViewModel.NodeModel; this.nodeModel = nodeViewModel.NodeModel as CodeBlockNodeModel; if (nodeModel == null) { throw new InvalidOperationException( "Should not be used for nodes other than code block"); } // Determines if this editor is created for a new code block node. // In cases like an undo/redo operation, the editor is created for // an existing code block node. createdForNewCodeBlock = string.IsNullOrEmpty(nodeModel.Code); // Register text editing events this.InnerTextEditor.TextChanged += InnerTextEditor_TextChanged; this.InnerTextEditor.TextArea.LostFocus += TextArea_LostFocus; nodeView.Unloaded += (obj, args) => isDisposed = true; // the code block should not be in focus upon undo/redo actions on node if (this.nodeModel.ShouldFocus) { this.Loaded += (obj, args) => this.InnerTextEditor.TextArea.Focus(); } // Register auto-completion callbacks this.InnerTextEditor.TextArea.TextEntering += OnTextAreaTextEntering; this.InnerTextEditor.TextArea.TextEntered += OnTextAreaTextEntered; InitializeSyntaxHighlighter(); }
/// <summary> /// Returns the index of the port corresponding to the variable name given /// </summary> /// <param name="variableName"> Name of the variable corresponding to an input port </param> /// <returns> Index of the required port in the InPorts collection </returns> public static int GetInportIndex(CodeBlockNodeModel cbn, string variableName) { return cbn.inputIdentifiers.IndexOf(variableName); }
/// <summary> /// Paste ISelectable objects from the clipboard to the workspace. /// </summary> public void Paste() { //clear the selection so we can put the //paste contents in DynamoSelection.Instance.ClearSelection(); //make a lookup table to store the guids of the //old models and the guids of their pasted versions var modelLookup = new Dictionary<Guid, ModelBase>(); //make a list of all newly created models so that their //creations can be recorded in the undo recorder. var createdModels = new List<ModelBase>(); var nodes = ClipBoard.OfType<NodeModel>(); var connectors = ClipBoard.OfType<ConnectorModel>(); var notes = ClipBoard.OfType<NoteModel>(); var annotations = ClipBoard.OfType<AnnotationModel>(); var minX = Double.MaxValue; var minY = Double.MaxValue; // Create the new NoteModel's var newNoteModels = new List<NoteModel>(); foreach (var note in notes) { var noteModel = new NoteModel(note.X, note.Y, note.Text, Guid.NewGuid()); //Store the old note as Key and newnote as value. modelLookup.Add(note.GUID,noteModel); newNoteModels.Add(noteModel); minX = Math.Min(note.X, minX); minY = Math.Min(note.Y, minY); } var xmlDoc = new XmlDocument(); // Create the new NodeModel's var newNodeModels = new List<NodeModel>(); foreach (var node in nodes) { NodeModel newNode; if (CurrentWorkspace is HomeWorkspaceModel && (node is Symbol || node is Output)) { var symbol = (node is Symbol ? (node as Symbol).InputSymbol : (node as Output).Symbol); var code = (string.IsNullOrEmpty(symbol) ? "x" : symbol) + ";"; newNode = new CodeBlockNodeModel(code, node.X, node.Y, LibraryServices, CurrentWorkspace.ElementResolver); } else { var dynEl = node.Serialize(xmlDoc, SaveContext.Copy); newNode = NodeFactory.CreateNodeFromXml(dynEl, SaveContext.Copy, CurrentWorkspace.ElementResolver); } var lacing = node.ArgumentLacing.ToString(); newNode.UpdateValue(new UpdateValueParams("ArgumentLacing", lacing)); if (!string.IsNullOrEmpty(node.NickName)) newNode.NickName = node.NickName; modelLookup.Add(node.GUID, newNode); newNodeModels.Add( newNode ); minX = Math.Min(node.X, minX); minY = Math.Min(node.Y, minY); } // Move all of the notes and nodes such that they are aligned with // the top left of the workspace var workspaceX = -CurrentWorkspace.X / CurrentWorkspace.Zoom; var workspaceY = -CurrentWorkspace.Y / CurrentWorkspace.Zoom; // Provide a small offset when pasting so duplicate pastes aren't directly on top of each other CurrentWorkspace.IncrementPasteOffset(); var shiftX = workspaceX - minX + CurrentWorkspace.CurrentPasteOffset; var shiftY = workspaceY - minY + CurrentWorkspace.CurrentPasteOffset; foreach (var model in newNodeModels.Concat<ModelBase>(newNoteModels)) { model.X = model.X + shiftX; model.Y = model.Y + shiftY; } // Add the new NodeModel's to the Workspace foreach (var newNode in newNodeModels) { CurrentWorkspace.AddAndRegisterNode(newNode, false); createdModels.Add(newNode); AddToSelection(newNode); } // TODO: is this required? OnRequestLayoutUpdate(this, EventArgs.Empty); // Add the new NoteModel's to the Workspace foreach (var newNote in newNoteModels) { CurrentWorkspace.AddNote(newNote, false); createdModels.Add(newNote); AddToSelection(newNote); } ModelBase start; ModelBase end; var newConnectors = from c in connectors // If the guid is in nodeLookup, then we connect to the new pasted node. Otherwise we // re-connect to the original. let startNode = modelLookup.TryGetValue(c.Start.Owner.GUID, out start) ? start as NodeModel : CurrentWorkspace.Nodes.FirstOrDefault(x => x.GUID == c.Start.Owner.GUID) let endNode = modelLookup.TryGetValue(c.End.Owner.GUID, out end) ? end as NodeModel : CurrentWorkspace.Nodes.FirstOrDefault(x => x.GUID == c.End.Owner.GUID) // Don't make a connector if either end is null. where startNode != null && endNode != null select ConnectorModel.Make(startNode, endNode, c.Start.Index, c.End.Index); createdModels.AddRange(newConnectors); //Grouping depends on the selected node models. //so adding the group after nodes / notes are added to workspace. //select only those nodes that are part of a group. var newAnnotations = new List<AnnotationModel>(); foreach (var annotation in annotations) { var annotationNodeModel = new List<NodeModel>(); var annotationNoteModel = new List<NoteModel>(); //checked condition here that supports pasting of multiple groups foreach (var models in annotation.SelectedModels) { ModelBase mbase; modelLookup.TryGetValue(models.GUID, out mbase); if (mbase is NodeModel) { annotationNodeModel.Add(mbase as NodeModel); } if (mbase is NoteModel) { annotationNoteModel.Add(mbase as NoteModel); } } var annotationModel = new AnnotationModel(annotationNodeModel, annotationNoteModel) { GUID = Guid.NewGuid(), AnnotationText = annotation.AnnotationText, Background = annotation.Background, FontSize = annotation.FontSize }; newAnnotations.Add(annotationModel); } // Add the new Annotation's to the Workspace foreach (var newAnnotation in newAnnotations) { CurrentWorkspace.AddAnnotation(newAnnotation); createdModels.Add(newAnnotation); AddToSelection(newAnnotation); } // Record models that are created as part of the command. CurrentWorkspace.RecordCreatedModels(createdModels); }
/// <summary> /// Forms new connections from the external nodes to the Node To Code Node, /// based on the connectors passed as inputs. /// </summary> /// <param name="externalInputConnections">List of connectors to remake, along with the port names of the new port</param> /// <param name="cbn">The new Node To Code created Code Block Node</param> private List<ConnectorModel> ReConnectInputConnections( Dictionary<ConnectorModel, string> externalInputConnections, CodeBlockNodeModel cbn) { List<ConnectorModel> newConnectors = new List<ConnectorModel>(); foreach (var kvp in externalInputConnections) { var connector = kvp.Key; var variableName = kvp.Value; var endPortIndex = CodeBlockNodeModel.GetInportIndex(cbn, variableName); if (endPortIndex < 0) continue; if (Connectors.Any(c => c.End == cbn.InPorts[endPortIndex])) continue; var newConnector = ConnectorModel.Make( connector.Start.Owner, cbn, connector.Start.Index, endPortIndex); newConnectors.Add(newConnector); } return newConnectors; }
/// <summary> /// Forms new connections from the external nodes to the Node To Code Node, /// based on the connectors passed as inputs. /// </summary> /// <param name="externalOutputConnections">List of connectors to remake, along with the port names of the new port</param> /// <param name="cbn">The new Node To Code created Code Block Node</param> private List<ConnectorModel> ReConnectOutputConnections(Dictionary<ConnectorModel, string> externalOutputConnections, CodeBlockNodeModel cbn) { List<ConnectorModel> newConnectors = new List<ConnectorModel>(); foreach (var kvp in externalOutputConnections) { var connector = kvp.Key; var variableName = kvp.Value; //Get the start and end idex for the ports for the connection var portModel = cbn.OutPorts.FirstOrDefault( port => cbn.GetRawAstIdentifierForOutputIndex(port.Index).Value.Equals(variableName)); if (portModel == null) continue; //Make the new connection and then record and add it var newConnector = ConnectorModel.Make( cbn, connector.End.Owner, portModel.Index, connector.End.Index); newConnectors.Add(newConnector); } return newConnectors; }
internal void ConvertNodesToCodeInternal(EngineController engineController) { var selectedNodes = DynamoSelection.Instance .Selection .OfType<NodeModel>() .Where(n => n.IsConvertible); if (!selectedNodes.Any()) return; var cliques = NodeToCodeUtils.GetCliques(selectedNodes).Where(c => !(c.Count == 1 && c.First() is CodeBlockNodeModel)); var codeBlockNodes = new List<CodeBlockNodeModel>(); //UndoRedo Action Group---------------------------------------------- NodeToCodeUndoHelper undoHelper = new NodeToCodeUndoHelper(); // using (UndoRecorder.BeginActionGroup()) { foreach (var nodeList in cliques) { //Create two dictionarys to store the details of the external connections that have to //be recreated after the conversion var externalInputConnections = new Dictionary<ConnectorModel, string>(); var externalOutputConnections = new Dictionary<ConnectorModel, string>(); //Also collect the average X and Y co-ordinates of the different nodes int nodeCount = nodeList.Count; var nodeToCodeResult = engineController.ConvertNodesToCode(this.nodes, nodeList); #region Step I. Delete all nodes and their connections double totalX = 0, totalY = 0; foreach (var node in nodeList) { #region Step I.A. Delete the connections for the node foreach (var connector in node.AllConnectors.ToList()) { if (!IsInternalNodeToCodeConnection(nodeList, connector)) { //If the connector is an external connector, the save its details //for recreation later var startNode = connector.Start.Owner; int index = startNode.OutPorts.IndexOf(connector.Start); //We use the varibleName as the connection between the port of the old Node //to the port of the new node. var variableName = startNode.GetAstIdentifierForOutputIndex(index).Value; //Store the data in the corresponding dictionary if (startNode == node) { if (nodeToCodeResult.OutputMap.ContainsKey(variableName)) variableName = nodeToCodeResult.OutputMap[variableName]; externalOutputConnections.Add(connector, variableName); } else { if (nodeToCodeResult.InputMap.ContainsKey(variableName)) variableName = nodeToCodeResult.InputMap[variableName]; externalInputConnections.Add(connector, variableName); } } //Delete the connector undoHelper.RecordDeletion(connector); connector.Delete(); } #endregion #region Step I.B. Delete the node totalX += node.X; totalY += node.Y; undoHelper.RecordDeletion(node); Nodes.Remove(node); #endregion } #endregion #region Step II. Create the new code block node var outputVariables = externalOutputConnections.Values; var newResult = NodeToCodeUtils.ConstantPropagationForTemp(nodeToCodeResult, outputVariables); NodeToCodeUtils.ReplaceWithUnqualifiedName(engineController.LibraryServices.LibraryManagementCore, newResult.AstNodes); var codegen = new ProtoCore.CodeGenDS(newResult.AstNodes); var code = codegen.GenerateCode(); var codeBlockNode = new CodeBlockNodeModel( code, System.Guid.NewGuid(), totalX / nodeCount, totalY / nodeCount, engineController.LibraryServices); undoHelper.RecordCreation(codeBlockNode); Nodes.Add(codeBlockNode); this.RegisterNode(codeBlockNode); codeBlockNodes.Add(codeBlockNode); #endregion #region Step III. Recreate the necessary connections var newInputConnectors = ReConnectInputConnections(externalInputConnections, codeBlockNode); foreach (var connector in newInputConnectors) { undoHelper.RecordCreation(connector); } var newOutputConnectors = ReConnectOutputConnections(externalOutputConnections, codeBlockNode); foreach (var connector in newOutputConnectors) { undoHelper.RecordCreation(connector); } #endregion } } undoHelper.ApplyActions(UndoRecorder); DynamoSelection.Instance.ClearSelection(); DynamoSelection.Instance.Selection.AddRange(codeBlockNodes); RequestRun(); }
/// <summary> /// Paste ISelectable objects from the clipboard to the workspace. /// </summary> /// <param name="parameters"></param> public void Paste(object parameters) { //make a lookup table to store the guids of the //old nodes and the guids of their pasted versions var nodeLookup = new Dictionary<Guid, Guid>(); //make a list of all newly created models so that their //creations can be recorded in the undo recorder. var createdModels = new List<ModelBase>(); //clear the selection so we can put the //paste contents in DynamoSelection.Instance.ClearSelection(); var nodes = this.ClipBoard.OfType<NodeModel>(); var connectors = this.ClipBoard.OfType<ConnectorModel>(); foreach (NodeModel node in nodes) { //create a new guid for us to use Guid newGuid = Guid.NewGuid(); nodeLookup.Add(node.GUID, newGuid); string nodeName = node.GetType().ToString(); if (node is Function) nodeName = ((node as Function).Definition.FunctionId).ToString(); #if USE_DSENGINE else if (node is DSFunction) nodeName = ((node as DSFunction).Controller.MangledName); else if (node is DSVarArgFunction) nodeName = ((node as DSVarArgFunction).Controller.MangledName); #endif var xmlDoc = new XmlDocument(); NodeModel newNode; if (CurrentWorkspace is HomeWorkspaceModel && (node is Symbol || node is Output)) { var symbol = (node is Symbol ? (node as Symbol).InputSymbol : (node as Output).Symbol); var code = (string.IsNullOrEmpty(symbol) ? "x" : symbol) + ";"; newNode = new CodeBlockNodeModel(CurrentWorkspace, code); CurrentWorkspace.AddNode(newNode, newGuid, node.X, node.Y + 100, false, false); } else { var dynEl = xmlDoc.CreateElement(node.GetType().ToString()); xmlDoc.AppendChild(dynEl); node.Save(xmlDoc, dynEl, SaveContext.Copy); newNode = CurrentWorkspace.AddNode( newGuid, nodeName, node.X, node.Y + 100, false, false, dynEl); } createdModels.Add(newNode); newNode.ArgumentLacing = node.ArgumentLacing; if (!string.IsNullOrEmpty(node.NickName)) { newNode.NickName = node.NickName; } } OnRequestLayoutUpdate(this, EventArgs.Empty); foreach (ConnectorModel c in connectors) { var connectionData = new Dictionary<string, object>(); // if in nodeLookup, the node is paste. otherwise, use the existing node guid Guid startGuid = Guid.Empty; Guid endGuid = Guid.Empty; startGuid = nodeLookup.TryGetValue(c.Start.Owner.GUID, out startGuid) ? startGuid : c.Start.Owner.GUID; endGuid = nodeLookup.TryGetValue(c.End.Owner.GUID, out endGuid) ? endGuid : c.End.Owner.GUID; var startNode = CurrentWorkspace.Nodes.FirstOrDefault(x => x.GUID == startGuid); var endNode = CurrentWorkspace.Nodes.FirstOrDefault(x => x.GUID == endGuid); // do not form connector if the end nodes are null if (startNode == null || endNode == null) { continue; } //don't let users paste connectors between workspaces if (startNode.Workspace != CurrentWorkspace) { continue; } createdModels.Add(CurrentWorkspace.AddConnection(startNode, endNode, c.Start.Index, c.End.Index)); } //process the queue again to create the connectors //DynamoCommands.ProcessCommandQueue(); var notes = this.ClipBoard.OfType<NoteModel>(); foreach (NoteModel note in notes) { var newGUID = Guid.NewGuid(); var sameSpace = CurrentWorkspace.Notes.Any(x => x.GUID == note.GUID); var newX = sameSpace ? note.X + 20 : note.X; var newY = sameSpace ? note.Y + 20 : note.Y; createdModels.Add(CurrentWorkspace.AddNote(false, newX, newY, note.Text, newGUID)); // TODO: Why can't we just add "noteData" instead of doing a look-up? AddToSelection(CurrentWorkspace.Notes.FirstOrDefault(x => x.GUID == newGUID)); } foreach (var de in nodeLookup) { AddToSelection(CurrentWorkspace.Nodes.FirstOrDefault(x => x.GUID == de.Value)); } // Record models that are created as part of the command. CurrentWorkspace.RecordCreatedModels(createdModels); }
internal void ConvertNodesToCodeInternal(Guid nodeId) { IEnumerable<NodeModel> nodes = DynamoSelection.Instance.Selection.OfType<NodeModel>().Where(n => n.IsConvertible); if (!nodes.Any()) return; Dictionary<string, string> variableNameMap; string code = dynSettings.Controller.EngineController.ConvertNodesToCode(nodes, out variableNameMap); //UndoRedo Action Group---------------------------------------------- UndoRecorder.BeginActionGroup(); #region Step I. Delete all nodes and their connections //Create two dictionarys to store the details of the external connections that have to //be recreated after the conversion var externalInputConnections = new Dictionary<ConnectorModel, string>(); var externalOutputConnections = new Dictionary<ConnectorModel, string>(); //Also collect the average X and Y co-ordinates of the different nodes var nodeList = nodes.ToList(); int nodeCount = nodeList.Count; double totalX = 0, totalY = 0; for (int i = 0; i < nodeList.Count; ++i) { var node = nodeList[i]; #region Step I.A. Delete the connections for the node var connectors = node.AllConnectors as IList<ConnectorModel>; if (null == connectors) { connectors = node.AllConnectors.ToList(); } for (int n = 0; n < connectors.Count(); ++n) { var connector = connectors[n]; if (!IsInternalNodeToCodeConnection(connector)) { //If the connector is an external connector, the save its details //for recreation later var startNode = connector.Start.Owner; int index = startNode.OutPorts.IndexOf(connector.Start); //We use the varibleName as the connection between the port of the old Node //to the port of the new node. var variableName = startNode.GetAstIdentifierForOutputIndex(index).Value; if (variableNameMap.ContainsKey(variableName)) variableName = variableNameMap[variableName]; //Store the data in the corresponding dictionary if (startNode == node) externalOutputConnections.Add(connector, variableName); else externalInputConnections.Add(connector, variableName); } //Delete the connector UndoRecorder.RecordDeletionForUndo(connector); connector.NotifyConnectedPortsOfDeletion(); Connectors.Remove(connector); } #endregion #region Step I.B. Delete the node totalX += node.X; totalY += node.Y; UndoRecorder.RecordDeletionForUndo(node); Nodes.Remove(node); #endregion } #endregion #region Step II. Create the new code block node var codeBlockNode = new CodeBlockNodeModel(code, nodeId, this, totalX / nodeCount, totalY / nodeCount); UndoRecorder.RecordCreationForUndo(codeBlockNode); Nodes.Add(codeBlockNode); #endregion #region Step III. Recreate the necessary connections ReConnectInputConnections(externalInputConnections, codeBlockNode); ReConnectOutputConnections(externalOutputConnections, codeBlockNode); #endregion UndoRecorder.EndActionGroup(); //End UndoRedo Action Group------------------------------------------ // select node var placedNode = dynSettings.Controller.DynamoViewModel.Model.Nodes.Find((node) => node.GUID == nodeId); if (placedNode != null) { DynamoSelection.Instance.ClearSelection(); DynamoSelection.Instance.Selection.Add(placedNode); } Modified(); }
/// <summary> /// Forms new connections from the external nodes to the Node To Code Node, /// based on the connectors passed as inputs. /// </summary> /// <param name="externalInputConnections">List of connectors to remake, along with the port names of the new port</param> /// <param name="codeBlockNode">The new Node To Code created Code Block Node</param> private void ReConnectInputConnections(Dictionary<ConnectorModel, string> externalInputConnections, CodeBlockNodeModel codeBlockNode) { foreach (var kvp in externalInputConnections) { var connector = kvp.Key; string variableName = kvp.Value; int startIndex = 0, endIndex = 0; //Find the start and end index of the ports for the connection startIndex = connector.Start.Owner.OutPorts.IndexOf(connector.Start); endIndex = CodeBlockNodeModel.GetInportIndex(codeBlockNode, variableName); //For inputs, a single node can be an input to multiple nodes in the code block node selection //After conversion, all these connecetions should become only 1 connection and not many //Hence for inputs, it is required to make sure that a certain type of connection has not //been created already. if (Connectors.Where(x => (x.Start == connector.Start && x.End == codeBlockNode.InPorts[endIndex])).FirstOrDefault() == null) { //Make the new connection and then record and add it var newConnector = ConnectorModel.Make(connector.Start.Owner, codeBlockNode, startIndex, endIndex, PortType.INPUT); this.Connectors.Add(newConnector); UndoRecorder.RecordCreationForUndo(newConnector); } } }
/// <summary> /// Forms new connections from the external nodes to the Node To Code Node, /// based on the connectors passed as inputs. /// </summary> /// <param name="externalOutputConnections">List of connectors to remake, along with the port names of the new port</param> /// <param name="codeBlockNode">The new Node To Code created Code Block Node</param> private void ReConnectOutputConnections(Dictionary<ConnectorModel, string> externalOutputConnections, CodeBlockNodeModel codeBlockNode) { foreach (var kvp in externalOutputConnections) { var connector = kvp.Key; string variableName = kvp.Value; int startIndex = 0, endIndex = 0; //Get the start and end idex for the ports for the connection endIndex = connector.End.Owner.InPorts.IndexOf(connector.End); int i = 0; for (i = 0; i < codeBlockNode.OutPorts.Count; i++) { if (codeBlockNode.GetAstIdentifierForOutputIndex(i).Value == variableName) break; } var portModel = codeBlockNode.OutPorts[i]; startIndex = codeBlockNode.OutPorts.IndexOf(portModel); //Make the new connection and then record and add it var newConnector = ConnectorModel.Make(codeBlockNode, connector.End.Owner, startIndex, endIndex, PortType.INPUT); this.Connectors.Add(newConnector); UndoRecorder.RecordCreationForUndo(newConnector); } }
private void UpdateCodeBlockNodeContent(CodeBlockNodeModel cbn, string value) { var command = new DynCmd.UpdateModelValueCommand(cbn.GUID, "Code", value); Controller.DynamoViewModel.ExecuteCommand(command); }
private void CreateCodeBlockNode(Point cursor) { // create node var node = new CodeBlockNodeModel(owningWorkspace.DynamoViewModel.Model.LibraryServices); owningWorkspace.DynamoViewModel.ExecuteCommand(new DynCmd.CreateNodeCommand(node, cursor.X, cursor.Y, false, true)); //correct node position node.X = (int)mouseDownPos.X - 92; node.Y = (int)mouseDownPos.Y - 31; }
private void UpdateCodeBlockNodeContent(CodeBlockNodeModel cbn, string value) { var command = new DynCmd.UpdateModelValueCommand(Guid.Empty, cbn.GUID, "Code", value); CurrentDynamoModel.ExecuteCommand(command); }
private CodeBlockNodeModel CreateCodeBlockNode() { var cbn = new CodeBlockNodeModel(CurrentDynamoModel.LibraryServices); var command = new DynCmd.CreateNodeCommand(cbn, 0, 0, true, false); CurrentDynamoModel.ExecuteCommand(command); Assert.IsNotNull(cbn); return cbn; }
/// <summary> /// Returns the index of the port corresponding to the variable name given /// </summary> /// <param name="variableName"> Name of the variable corresponding to an input port </param> /// <returns> Index of the required port in the InPorts collection </returns> public static int GetInportIndex(CodeBlockNodeModel cbn, string variableName) { return(cbn.inputIdentifiers.IndexOf(variableName)); }