/// <summary> /// Construct a view and respond to property changes on the model. /// </summary> /// <param name="model"></param> public ConnectorViewModel(WorkspaceViewModel workspace, ConnectorModel model) { this.workspaceViewModel = workspace; _model = model; _model.PropertyChanged += Model_PropertyChanged; _model.Start.Owner.PropertyChanged += StartOwner_PropertyChanged; _model.End.Owner.PropertyChanged += EndOwner_PropertyChanged; workspaceViewModel.DynamoViewModel.PropertyChanged += DynamoViewModel_PropertyChanged; Nodevm.PropertyChanged += nodeViewModel_PropertyChanged; Redraw(); }
public void TestSingleOutputNode() { // TODO pratapa: Test goes into infinite loop after Dictionary changes RunModel(@"core\multiout\singleoutput.dyn"); AssertPreviewValue("060e57e1-b889-4b94-a440-8adb0067ae79", null); var instanceNode = CurrentDynamoModel.CurrentWorkspace.Nodes.First(n => n.GUID.ToString().Equals("306c8777-ecff-4106-bfdd-dd331e61cf2b")); var dictNode = CurrentDynamoModel.CurrentWorkspace.Nodes.First(n => n.GUID.ToString().Equals("41271769-11b8-46fc-bb16-fffd022dc9bc")); var connector = ConnectorModel.Make(instanceNode, dictNode, 0, 0); RunCurrentModel(); AssertPreviewValue("060e57e1-b889-4b94-a440-8adb0067ae79", "green"); }
/// <summary> /// Deletes all connectors attached to this PortModel. /// </summary> public void DestroyConnectors() { if (Owner == null) { return; } while (Connectors.Any()) { ConnectorModel connector = Connectors[0]; connector.Delete(); } }
private void OnPortConnected(PortModel port, ConnectorModel connectorModel) { Tuple <int, NodeModel> input; if (watch.TryGetInput(watch.InPorts.IndexOf(connectorModel.End), out input)) { var oldId = astBeingWatched; astBeingWatched = input.Item2.GetAstIdentifierForOutputIndex(input.Item1); if (oldId != null && astBeingWatched.Value != oldId.Value) { // the input node has changed, we clear preview rootWatchViewModel.Children.Clear(); } } }
public ActionResult Create(ConnectorModel connectorModel) { try { if (connectorModel.CK_Id > 0) { return(StatusCode(StatusCodes.Status400BadRequest, "Providing custom CK_Id is not allowed, Connector.CK_Id is Auto-Generated !")); } var connector = _Mapper.Map <Connector>(connectorModel); connector = _ConnectorService.CreateConnector(connector); return(Ok(_Mapper.Map <ConnectorModel>(connector))); } catch (ConnectorMaxCurrentExceedGroupCapacityException ex) { return(StatusCode(StatusCodes.Status400BadRequest, ex.Message)); } catch (ConnectorsMaxCurrentExceedGroupCapacityException ex) { //get chargeStation var chargeStation = _ChargeStationService.GetChargeStation(connectorModel.ChargeStationId); //get connectors of group var connectorsOFGroup = _ConnectorService.GetConnectorsByGroup(chargeStation.GroupId); //get suggestions var suggestions = _Suggester.GetSuggestions(connectorsOFGroup, connectorModel.MaxCurrent); //Create suggestionResponse var response = new SuggestionResponse { ErrorMessage = ex.Message }; response.Suggestions = _Mapper.Map <List <SuggestionModel> >(suggestions); return(BadRequest(response)); } catch (DataException ex) { return(StatusCode(StatusCodes.Status400BadRequest, ex.Message)); } catch (DomainValidationException ex) { return(StatusCode(StatusCodes.Status400BadRequest, ex.Message)); } catch (Exception) { return(StatusCode(StatusCodes.Status500InternalServerError)); } }
public void TestOnDeletionStarted() { //Arrange //This will subscribe our local method to the DeletionStarted event CurrentDynamoModel.DeletionStarted += CurrentDynamoModel_DeletionStarted; //This create a new Code Block node and update the content var codeBlockNode0 = CreateCodeBlockNode(); UpdateCodeBlockNodeContent(codeBlockNode0, @"true;"); // Create the watch node. var watch = new Watch(); var command = new DynCmd.CreateNodeCommand( watch, 0, 0, true, false); CurrentDynamoModel.ExecuteCommand(command); // Connect the two nodes ConnectorModel.Make(codeBlockNode0, watch, 0, 0); // Run Assert.DoesNotThrow(BeginRun); // Check that we have two nodes in the current workspace, the Watch node and the CodeBlock Assert.AreEqual(2, CurrentDynamoModel.CurrentWorkspace.Nodes.Count()); // Delete the code block node, internally this will call the OnDeletionStarted() method var nodeCodeBlock = new List <ModelBase> { codeBlockNode0 }; CurrentDynamoModel.DeleteModelInternal(nodeCodeBlock); // Check that we have only the watch in the current workspace Assert.AreEqual(1, CurrentDynamoModel.CurrentWorkspace.Nodes.Count()); Assert.AreEqual("Watch", CurrentDynamoModel.CurrentWorkspace.Nodes.FirstOrDefault().GetType().Name); // Try to delete the Watch node var nodeWatch = new List <ModelBase> { watch }; CurrentDynamoModel.DeleteModelInternal(nodeWatch); CurrentDynamoModel.DeletionStarted -= CurrentDynamoModel_DeletionStarted; Assert.IsTrue(deletionStarted); }
internal void EndConnection(Guid nodeId, int portIndex, PortType portType) { int index = portIndex; bool isInPort = portType == PortType.INPUT; NodeModel node = Model.GetModelInternal(nodeId) as NodeModel; PortModel portModel = isInPort ? node.InPorts[index] : node.OutPorts[index]; ConnectorModel connectorToRemove = null; // Remove connector if one already exists if (portModel.Connectors.Count > 0 && portModel.PortType == PortType.INPUT) { connectorToRemove = portModel.Connectors[0]; Model.Connectors.Remove(connectorToRemove); portModel.Disconnect(connectorToRemove); var startPort = connectorToRemove.Start; startPort.Disconnect(connectorToRemove); } // Create the new connector model var start = this.activeConnector.ActiveStartPort; var end = portModel; // We could either connect from an input port to an output port, or // another way around (in which case we swap first and second ports). PortModel firstPort = start, second = end; if (portModel.PortType != PortType.INPUT) { firstPort = end; second = start; } ConnectorModel newConnectorModel = this.Model.AddConnection(firstPort.Owner, second.Owner, firstPort.Index, second.Index, PortType.INPUT); // Record the creation of connector in the undo recorder. var models = new Dictionary <ModelBase, UndoRedoRecorder.UserAction>(); if (connectorToRemove != null) { models.Add(connectorToRemove, UndoRedoRecorder.UserAction.Deletion); } models.Add(newConnectorModel, UndoRedoRecorder.UserAction.Creation); Model.RecordModelsForUndo(models); this.SetActiveConnector(null); }
private void Model_PortConnected(PortModel portModel, ConnectorModel connector) { switch (portModel.PortType) { case PortType.Input: var ifcModels = NodeModel.GetCachedInput <IfcModel>(portModel.Index, ModelEngineController); // Autofix extension if unique if (1 == ifcModels.Length) { NodeModel.Selected = ifcModels.FirstOrDefault()?.FormatExtension; } break; case PortType.Output: break; } }
private static void OnSelectedTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Slot slot = (Slot)d; SlaveType type; PluginChangedEventArgs args; ConnectorModel model = slot.element.ConnectorModel; if (slot.loading) { return; } if ((e.OldValue != null || e.NewValue == null) && slot.ActiveModel != null) { model.WorkspaceModel.ModifyModel(new DeletePluginModelOperation(slot.ActiveModel)); model.WorkspaceModel.ModifyModel(new DeleteConnectionModelOperation(slot.activeConnectionModel)); args = new PluginChangedEventArgs(slot.ActiveModel.Plugin, slot.ActiveModel.GetName(), DisplayPluginMode.Normal); slot.MyEditor.onSelectedPluginChanged(args); slot.ActiveModel = null; } if (e.OldValue != null && e.NewValue != null) { if (((SlaveType)e.OldValue).Type.IsAssignableFrom(((SlaveType)e.NewValue).Type)) { return; } } if (e.NewValue == null) { return; } type = e.NewValue as SlaveType; var v = (PluginModel)model.WorkspaceModel.ModifyModel(new NewPluginModelOperation(new Point(0, 0), (double)0, (double)0, type.Type)); slot.ActiveModel = v; var f = v.GetInputConnectors().Single(a => a.ConnectorType.IsAssignableFrom(slot.element.ConnectorModel.ConnectorType)); slot.activeConnectionModel = (ConnectionModel)model.WorkspaceModel.ModifyModel(new NewConnectionModelOperation(model, f, f.ConnectorType)); args = new PluginChangedEventArgs(slot.ActiveModel.Plugin, slot.ActiveModel.GetName(), DisplayPluginMode.Normal); slot.MyEditor.onSelectedPluginChanged(args); }
/// <summary> /// Disconnect the specified connector from this port. /// </summary> /// <param name="connector">Connector.</param> public virtual void Disconnect(ConnectorModel connector) { if (connectors.Remove(connector) == false) { Debug.Log("could not disconnect connect, could not find it in connector list"); return; } if (connectors.Count == 0) { IsConnected = false; } //throw the event for a connection OnPortDisconnected(EventArgs.Empty); //Owner.ValidateConnections (); }
/// <summary> /// Handler for the model's ConnectorDeleted event. /// </summary> /// <param name="connector"></param> private void DynamoModel_ConnectorDeleted(ConnectorModel connector) { // TODO: Ian should remove this when the CBN reconnection bug is solved. /*if (connector.Start.Owner.GetType() == typeof(CodeBlockNodeModel)) * { * return; * } * * //we are given the connector that was deleted * //if it's end node still exists, clear the package for * //the node and trigger an update. * if (connector.End != null) * connector.End.Owner.ClearRenderPackages(); * * //tell the watches that they require re-binding. * QueueRenderTask();*/ }
internal void EndConnection(Guid nodeId, int portIndex, PortType portType) { int index = portIndex; bool isInPort = portType == PortType.INPUT; NodeModel node = _model.GetModelInternal(nodeId) as NodeModel; PortModel portModel = isInPort ? node.InPorts[index] : node.OutPorts[index]; // Remove connector if one already exists if (portModel.Connectors.Count > 0 && portModel.PortType == PortType.INPUT) { var connToRemove = portModel.Connectors[0]; _model.Connectors.Remove(connToRemove); portModel.Disconnect(connToRemove); var startPort = connToRemove.Start; startPort.Disconnect(connToRemove); } // Create the new connector model var start = this.activeConnector.ActiveStartPort; var end = portModel; // We could either connect from an input port to an output port, or // another way around (in which case we swap first and second ports). PortModel firstPort = start, second = end; if (portModel.PortType != PortType.INPUT) { firstPort = end; second = start; } ConnectorModel newConnectorModel = ConnectorModel.Make(firstPort.Owner, second.Owner, firstPort.Index, second.Index, PortType.INPUT); if (newConnectorModel != null) // Add to the current workspace { _model.Connectors.Add(newConnectorModel); } // Record the creation of connector in the undo recorder. _model.RecordCreatedModel(newConnectorModel); this.SetActiveConnector(null); }
/// <summary> /// Handler for the model's ConnectorDeleted event. /// </summary> /// <param name="connector"></param> void DynamoModel_ConnectorDeleted(ConnectorModel connector) { // TODO: Ian should remove this when the CBN reconnection bug is solved. if (connector.Start.Owner.GetType() == typeof(CodeBlockNodeModel)) { return; } //we are given the connector that was deleted //if it's end node still exists, clear the package for //the node and trigger an update. if (connector.End != null) { connector.End.Owner.ClearRenderPackages(); } //tell the watches that they require re-binding. OnVisualizationUpdateComplete(this, EventArgs.Empty); }
/// <summary> /// Places watch node at the midpoint of the connector /// </summary> internal List <ModelBase> PlaceWatchNode(ConnectorModel connector, IEnumerable <Point> connectorPinLocations, List <ModelBase> allDeletedModels) { var createdModels = new List <ModelBase>(); NodeModel startNode = ViewModel.ConnectorModel.Start.Owner; NodeModel endNode = ViewModel.ConnectorModel.End.Owner; this.Dispatcher.Invoke(() => { var watchNode = new Watch(); var nodeX = CurrentPosition.X - (watchNode.Width / 2); var nodeY = CurrentPosition.Y - (watchNode.Height / 2); DynamoModel.ExecuteCommand(new DynamoModel.CreateNodeCommand(watchNode, nodeX, nodeY, false, false)); createdModels.Add(watchNode); WireNewNode(DynamoModel, startNode, endNode, watchNode, connector, connectorPinLocations, createdModels, allDeletedModels); }); return(createdModels); }
internal void BeginConnection(Guid nodeId, int portIndex, PortType portType) { int index = portIndex; bool isInPort = portType == PortType.INPUT; NodeModel node = _model.GetModelInternal(nodeId) as NodeModel; PortModel portModel = isInPort ? node.InPorts[index] : node.OutPorts[index]; // Test if port already has a connection, if so grab it and begin connecting // to somewhere else (we don't allow the grabbing of the start connector). if (portModel.Connectors.Count > 0 && portModel.Connectors[0].Start != portModel) { // Define the new active connector var c = new ConnectorViewModel(portModel.Connectors[0].Start); this.SetActiveConnector(c); // Disconnect the connector model from its start and end ports // and remove it from the connectors collection. This will also // remove the view model. ConnectorModel connector = portModel.Connectors[0]; if (_model.Connectors.Contains(connector)) { List <ModelBase> models = new List <ModelBase>(); models.Add(connector); _model.RecordAndDeleteModels(models); connector.NotifyConnectedPortsOfDeletion(); } } else { try { // Create a connector view model to begin drawing var connector = new ConnectorViewModel(portModel); this.SetActiveConnector(connector); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } }
public void TestKeepReferenceThisAttribute() { // Test KeepReferenceThisAttribute could avoid a C# object from // being disposed even it is out function scope. // // The .dyn file uses ReferenceThis from FFITarget.dll. Note the // return value of GetItems() has reference to "this" object: // // class ReferenceThis { // .... // public IEnumerable<ReferenceThisItem> GetItems() { // return new [] { new ReferenceThisItem(this), ... }; // } // } // // So if we call GetItems() in a function, refThis object will be // disposed and returned object has reference to disposed // ReferenceThis. // // def foo() { // refThis = ReferenceThis(); // return = refThis.GetItems(); // } // // But if applying KeepReferenceThisAttribute, refThis will be // referenced in the returned object and won't be disposed. This // test case is to verify ReferenceThis.Disposed is false when // returns from a function. var dynFilePath = Path.Combine(TestDirectory, @"core\dsevaluation\referenceThis.dyn"); OpenModel(dynFilePath); var node1 = CurrentDynamoModel.CurrentWorkspace.Nodes.OfType <Graph.Nodes.CustomNodes.Function>().FirstOrDefault(); var node2 = CurrentDynamoModel.CurrentWorkspace.Nodes.OfType <DSFunction>().FirstOrDefault(); // Not connect at the beginning to ensure GC() is invoked. ConnectorModel.Make(node1, node2, 0, 0); RunCurrentModel(); AssertPreviewValue("763c4e98-dbe0-4bb7-b00f-69e5b79b09b0", new object[] { false, false }); }
/// <summary> /// Rewires nodes and newly placed watch node between them. /// </summary> /// <param name="dynamoModel"></param> /// <param name="startNode"></param> /// <param name="endNode"></param> /// <param name="watchNodeModel"></param> private void WireNewNode( DynamoModel dynamoModel, NodeModel startNode, NodeModel endNode, NodeModel watchNodeModel, ConnectorModel connector, IEnumerable <Point> connectorPinLocations, List <ModelBase> allCreatedModels, List <ModelBase> allDeletedModels) { (int startIndex, int endIndex) = GetPortIndex(connector); // Connect startNode and watch node dynamoModel.ExecuteCommand(new DynamoModel.MakeConnectionCommand(startNode.GUID, startIndex, PortType.Output, DynamoModel.MakeConnectionCommand.Mode.Begin)); dynamoModel.ExecuteCommand(new DynamoModel.MakeConnectionCommand(watchNodeModel.GUID, 0, PortType.Input, DynamoModel.MakeConnectionCommand.Mode.End)); // Connect watch node and endNode dynamoModel.ExecuteCommand(new DynamoModel.MakeConnectionCommand(watchNodeModel.GUID, 0, PortType.Output, DynamoModel.MakeConnectionCommand.Mode.Begin)); dynamoModel.ExecuteCommand(new DynamoModel.MakeConnectionCommand(endNode.GUID, endIndex, PortType.Input, DynamoModel.MakeConnectionCommand.Mode.End)); PlacePinsOnWires(startNode, watchNodeModel, connector, connectorPinLocations, allCreatedModels, allDeletedModels); }
public void Disconnect(ConnectorModel connector, bool silent = false) { if (!connectors.Contains(connector)) { return; } //throw the event for a disconnection if (!silent) { OnPortDisconnected(); } connectors.Remove(connector); if (connectors.Count == 0) { IsConnected = false; } Owner.ValidateConnections(); }
private void OnPortConnected(PortModel port, ConnectorModel connectorModel) { Tuple <int, NodeModel> input; if (!watch.TryGetInput(watch.InPorts.IndexOf(connectorModel.End), out input) || astBeingComputed == null) { return; } var astBeingWatched = input.Item2.GetAstIdentifierForOutputIndex(input.Item1); if (astBeingComputed.Value != astBeingWatched.Value) { // the input node has changed, we clear preview rootWatchViewModel.Children.Clear(); } else { ResetWatch(); } }
private void PlacePinsOnWires(NodeModel startNode, NodeModel watchNodeModel, ConnectorModel connector, IEnumerable <Point> connectorPinLocations, List <ModelBase> allCreatedModels, List <ModelBase> allDeletedModels) { // Collect ports & connectors of newly connected nodes // so that old pins (that need to remain) can be transferred over correctly. PortModel startNodePort = startNode.OutPorts.FirstOrDefault(p => p.GUID == connector.Start.GUID); PortModel watchNodePort = watchNodeModel.OutPorts[0]; Graph.Connectors.ConnectorModel[] connectors = new Graph.Connectors.ConnectorModel[2]; connectors[0] = startNodePort.Connectors.FirstOrDefault(c => c.End.Owner.GUID == watchNodeModel.GUID && c.GUID != connector.GUID); connectors[1] = watchNodePort.Connectors.FirstOrDefault(c => c.Start.Owner.GUID == watchNodeModel.GUID && c.GUID != connector.GUID); if (connectors.Any(c => c is null)) { return; } allCreatedModels.AddRange(connectors); allDeletedModels.Add(connector); if (connectorPinLocations.Count() < 1) { return; } // Place each pin where required on the newly connected connectors. foreach (var connectorPinLocation in connectorPinLocations) { int wireIndex = ConnectorSegmentIndex(CurrentPosition, connectorPinLocation); ViewModel.PinConnectorPlacementFromWatchNode(connectors, wireIndex, connectorPinLocation, allCreatedModels); } }
/// <summary> /// Creates and initializes a ConnectorModel from its Xml representation. /// </summary> /// <param name="connEl">XmlElement for a ConnectorModel.</param> /// <param name="nodes">Dictionary to be used for looking up a NodeModel by it's Guid.</param> /// <returns>Returns the new instance of ConnectorModel loaded from XmlElement.</returns> public static ConnectorModel LoadConnectorFromXml(XmlElement connEl, IDictionary <Guid, NodeModel> nodes) { var helper = new XmlElementHelper(connEl); var guid = helper.ReadGuid("guid", Guid.NewGuid()); var guidStart = helper.ReadGuid("start"); var guidEnd = helper.ReadGuid("end"); int startIndex = helper.ReadInteger("start_index"); int endIndex = helper.ReadInteger("end_index"); //find the elements to connect NodeModel start; if (nodes.TryGetValue(guidStart, out start)) { NodeModel end; if (nodes.TryGetValue(guidEnd, out end)) { return(ConnectorModel.Make(start, end, startIndex, endIndex, guid)); } } return(null); }
public RewireConnectorOperation(ISketchItemDisplay pad, ConnectorModel model, Point p) { _connector = model; _pad = pad; IBoundedSketchItemModel ending = model.To; if (ending == null) { ending = model.From; } var start = ConnectorUtilities.ComputeCenter(ending.Bounds); _selector = new ConnectablePairSelector(start, p); _pad.Canvas.Children.Add(_selector); _selector.Visibility = Visibility.Visible; foreach (var ch in _pad.Canvas.Children.OfType <ISketchItemUI>()) { ch.Disable(); } _pad.Canvas.MouseMove += HandleMouseMove; _pad.Canvas.MouseDown += HandleMouseDown; _pad.Canvas.KeyDown += HandleKeyDown; }
public void ConnectorModelConnectTest() { //Arrange var outnode1 = new Output(); outnode1.Symbol = "out1"; var outnode2 = new Output(); outnode2.Symbol = "out2"; var numberNode = new DoubleInput(); numberNode.Value = "5"; //Act //It passes as parameters the same out port (start and end the same port) to the Connect(PortModel p) method then it won't create the connection to end. var connector1 = new ConnectorModel(numberNode.OutPorts.FirstOrDefault(), numberNode.OutPorts.FirstOrDefault(), Guid.NewGuid()); //It passes the second parameter (End) the output port then the Connect(PortModel p) method will try to connect an End port and it will fail var connector2 = new ConnectorModel(outnode2.InPorts.FirstOrDefault(), numberNode.OutPorts.FirstOrDefault(), Guid.NewGuid()); //The outnode2.InPorts has already nodes connected then when calling the Connect(PortModel p) method will remove the port connected var connector3 = new ConnectorModel(numberNode.OutPorts.FirstOrDefault(), outnode2.InPorts.FirstOrDefault(), Guid.NewGuid()); //Assert //The End will be null due that the connection from Start to End was not created (out port was passed to both parameters) Assert.IsNull(connector1.End); //The End will be null due that the connection from Start to End was not created (in port was passed to both parameters) Assert.IsNull(connector2.End); //It will create the connector from Start to End (removing the previous connected InPort). Assert.IsNotNull(connector3.Start); Assert.IsNotNull(connector3.End); }
private void RegisterConnector(ConnectorModel connector) { connector.Deleted += () => OnConnectorDeleted(connector); }
protected virtual void OnConnectorAdded(ConnectorModel obj) { RegisterConnector(obj); var handler = ConnectorAdded; if (handler != null) handler(obj); }
/// <summary> /// Checks whether the given connection is inside the node to code set or outside it. /// This determines if it should be redrawn(if it is external) or if it should be /// deleted (if it is internal) /// </summary> private static bool IsInternalNodeToCodeConnection(IEnumerable<NodeModel> nodes, ConnectorModel connector) { return nodes.Contains(connector.Start.Owner) && nodes.Contains(connector.End.Owner); }
protected virtual void PortConnectedHandler(PortModel arg1, ConnectorModel arg2) { // Do nothing for a standard node. }
/// <summary> /// Now that the portData has been set for the new ports, we recreate the connections we /// so mercilessly destroyed, restoring peace and balance to the world once again. /// </summary> /// <param name="inportConnections"></param> /// <param name="outportConnections"> List of the connections that were killed</param> private void LoadAndCreateConnectors(OrderedDictionary inportConnections, OrderedDictionary outportConnections) { //----------------------------Inputs--------------------------------- /* Input Port connections are matched only if the name is the same */ for (int i = 0; i < InPortData.Count; i++) { string varName = InPortData[i].ToolTipString; if (inportConnections.Contains(varName)) { if (inportConnections[varName] != null) { foreach (var startPortModel in (inportConnections[varName] as List <PortModel>)) { NodeModel startNode = startPortModel.Owner; var connector = ConnectorModel.Make( startNode, this, startPortModel.Index, i); } outportConnections[varName] = null; } } } //----------------------------Outputs-------------------------------- /*The matching is done in three parts: * Step 1: * First, it tries to match the connectors wrt to the defined * variable name. Hence it first checks to see if any of the old * variable names are present. If so, if there were any connectors * presnt then it makes the new connectors. As it iterates through * the new ports, it also finds the ports that didnt exist before */ List <int> undefinedIndices = new List <int>(); for (int i = 0; i < OutPortData.Count; i++) { string varName = OutPortData[i].ToolTipString; if (outportConnections.Contains(varName)) { if (outportConnections[varName] != null) { foreach (var endPortModel in (outportConnections[varName] as List <PortModel>)) { NodeModel endNode = endPortModel.Owner; var connector = ConnectorModel.Make(this, endNode, i, endPortModel.Index); } outportConnections[varName] = null; } } else { undefinedIndices.Add(i); } } /* * Step 2: * The second priority is to match the connections to the previous * indices. For all the ports that were not previously defined, it * now checks if that "numbered" port had any connections * previously, ie, if the old third port had 2 connections, then * these would go to the new 3rd port (if it is not a variable that * was defined before) */ for (int i = 0; i < undefinedIndices.Count; i++) { int index = undefinedIndices[i]; if (index < outportConnections.Count && outportConnections[index] != null) { foreach (PortModel endPortModel in (outportConnections[index] as List <PortModel>)) { NodeModel endNode = endPortModel.Owner; var connector = ConnectorModel.Make(this, endNode, index, endPortModel.Index); } outportConnections[index] = null; undefinedIndices.Remove(index); i--; } } /* * Step 2: * The final step. Now that the priorties are finished, the * function tries to reuse any existing connections by attaching * them to any ports that have not already been given connections */ List <List <PortModel> > unusedConnections = outportConnections.Values.Cast <List <PortModel> >() .Where(portModelList => portModelList != null) .ToList(); while (undefinedIndices.Count > 0 && unusedConnections.Count != 0) { foreach (PortModel endPortModel in unusedConnections[0]) { NodeModel endNode = endPortModel.Owner; ConnectorModel connector = ConnectorModel.Make( this, endNode, undefinedIndices[0], endPortModel.Index); } undefinedIndices.RemoveAt(0); unusedConnections.RemoveAt(0); } }
void Connectors_ConnectorDeleted(ConnectorModel c) { var connector = _connectors.FirstOrDefault(x => x.ConnectorModel == c); if (connector != null) _connectors.Remove(connector); }
protected virtual void OnConnectorDeleted(ConnectorModel obj) { if (hasNodeInSyncWithDefinition) { undoRecorder.RecordModelAsOffTrack(obj.GUID); } var handler = ConnectorDeleted; if (handler != null) handler(obj); }
/// <summary> /// Collapse a set of nodes in a given workspace. /// </summary> /// <param name="selectedNodes"> The function definition for the user-defined node </param> /// <param name="selectedNotes"> The note models in current selection </param> /// <param name="currentWorkspace"> The workspace where</param> /// <param name="args"></param> internal CustomNodeWorkspaceModel Collapse( IEnumerable <NodeModel> selectedNodes, IEnumerable <NoteModel> selectedNotes, WorkspaceModel currentWorkspace, FunctionNamePromptEventArgs args) { var selectedNodeSet = new HashSet <NodeModel>(selectedNodes); // Note that undoable actions are only recorded for the "currentWorkspace", // the nodes which get moved into "newNodeWorkspace" are not recorded for undo, // even in the new workspace. Their creations will simply be treated as part of // the opening of that new workspace (i.e. when a user opens a file, she will // not expect the nodes that show up to be undoable). // // After local nodes are moved into "newNodeWorkspace" as the result of // conversion, if user performs an undo, new set of nodes will be created in // "currentWorkspace" (not moving those nodes in the "newNodeWorkspace" back // into "currentWorkspace"). In another word, undo recording is on a per- // workspace basis, it does not work across different workspaces. // UndoRedoRecorder undoRecorder = currentWorkspace.UndoRecorder; CustomNodeWorkspaceModel newWorkspace; Debug.WriteLine("Current workspace has {0} nodes and {1} connectors", currentWorkspace.Nodes.Count(), currentWorkspace.Connectors.Count()); using (undoRecorder.BeginActionGroup()) { #region Determine Inputs and Outputs //Step 1: determine which nodes will be inputs to the new node var inputs = new HashSet <Tuple <NodeModel, int, Tuple <int, NodeModel> > >( selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.InPorts.Count) .Where(index => node.InPorts[index].Connectors.Any()) .Select(data => Tuple.Create(node, data, node.InputNodes[data])) .Where(input => !selectedNodeSet.Contains(input.Item3.Item2)))); var outputs = new HashSet <Tuple <NodeModel, int, Tuple <int, NodeModel> > >( selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.OutPorts.Count) .Where(index => node.OutPorts[index].Connectors.Any()) .SelectMany( data => node.OutputNodes[data].Where( output => !selectedNodeSet.Contains(output.Item2)) .Select(output => Tuple.Create(node, data, output))))); #endregion #region UI Positioning Calculations double avgX = selectedNodeSet.Average(node => node.X); double avgY = selectedNodeSet.Average(node => node.Y); double leftMost = selectedNodeSet.Min(node => node.X); double topMost = selectedNodeSet.Min(node => node.Y); double rightMost = selectedNodeSet.Max(node => node.X + node.Width); double leftShift = leftMost - 250; #endregion #region Handle full selected connectors // Step 2: Determine all the connectors whose start/end owners are // both in the selection set, and then move them from the current // workspace into the new workspace. var fullySelectedConns = new HashSet <ConnectorModel>( currentWorkspace.Connectors.Where( conn => { bool startSelected = selectedNodeSet.Contains(conn.Start.Owner); bool endSelected = selectedNodeSet.Contains(conn.End.Owner); return(startSelected && endSelected); })); foreach (var connector in fullySelectedConns) { undoRecorder.RecordDeletionForUndo(connector); connector.Delete(); } #endregion #region Handle partially selected connectors // Step 3: Partially selected connectors (either one of its start // and end owners is in the selection) are to be destroyed. var partiallySelectedConns = currentWorkspace.Connectors.Where( conn => selectedNodeSet.Contains(conn.Start.Owner) || selectedNodeSet.Contains(conn.End.Owner)).ToList(); foreach (var connector in partiallySelectedConns) { undoRecorder.RecordDeletionForUndo(connector); connector.Delete(); } #endregion #region Transfer nodes and connectors to new workspace var newNodes = new List <NodeModel>(); var newNotes = new List <NoteModel>(); var newAnnotations = new List <AnnotationModel>(); // Step 4: move all nodes and notes to new workspace remove from old // PB: This could be more efficiently handled by a copy paste, but we // are preservering the node foreach (var node in selectedNodeSet) { undoRecorder.RecordDeletionForUndo(node); currentWorkspace.RemoveAndDisposeNode(node); // Assign a new guid to this node, otherwise when node is // compiled to AST, literally it is still in global scope // instead of in function scope. node.GUID = Guid.NewGuid(); // shift nodes node.X = node.X - leftShift; node.Y = node.Y - topMost; newNodes.Add(node); } foreach (var note in selectedNotes) { undoRecorder.RecordDeletionForUndo(note); currentWorkspace.RemoveNote(note); note.GUID = Guid.NewGuid(); note.X = note.X - leftShift; note.Y = note.Y - topMost; newNotes.Add(note); } //Copy the group from newNodes foreach (var group in DynamoSelection.Instance.Selection.OfType <AnnotationModel>()) { undoRecorder.RecordDeletionForUndo(group); currentWorkspace.RemoveGroup(group); group.GUID = Guid.NewGuid(); group.Nodes = group.DeletedModelBases; newAnnotations.Add(group); } // Now all selected nodes already moved to custom workspace, // clear the selection. DynamoSelection.Instance.ClearSelection(); foreach (var conn in fullySelectedConns) { ConnectorModel.Make(conn.Start.Owner, conn.End.Owner, conn.Start.Index, conn.End.Index); } #endregion #region Process inputs var inConnectors = new List <Tuple <NodeModel, int> >(); var uniqueInputSenders = new Dictionary <Tuple <NodeModel, int>, Symbol>(); //Step 3: insert variables (reference step 1) foreach (var input in Enumerable.Range(0, inputs.Count).Zip(inputs, Tuple.Create)) { int inputIndex = input.Item1; NodeModel inputReceiverNode = input.Item2.Item1; int inputReceiverData = input.Item2.Item2; NodeModel inputNode = input.Item2.Item3.Item2; int inputData = input.Item2.Item3.Item1; Symbol node; var key = Tuple.Create(inputNode, inputData); if (uniqueInputSenders.ContainsKey(key)) { node = uniqueInputSenders[key]; } else { inConnectors.Add(Tuple.Create(inputNode, inputData)); node = new Symbol { InputSymbol = inputReceiverNode.InPorts[inputReceiverData].Name, X = 0 }; // Try to figure out the type of input of custom node // from the type of input of selected node. There are // two kinds of nodes whose input type are available: // function node and custom node. List <Library.TypedParameter> parameters = null; if (inputReceiverNode is EFunction) { var func = inputReceiverNode as EFunction; parameters = func.Controller.Definition.Parameters.ToList(); } else if (inputReceiverNode is DSFunctionBase) { var dsFunc = inputReceiverNode as DSFunctionBase; var funcDesc = dsFunc.Controller.Definition; parameters = funcDesc.Parameters.ToList(); if (funcDesc.Type == Engine.FunctionType.InstanceMethod || funcDesc.Type == Engine.FunctionType.InstanceProperty) { var dummyType = new ProtoCore.Type() { Name = funcDesc.ClassName }; var instanceParam = new TypedParameter(funcDesc.ClassName, dummyType); parameters.Insert(0, instanceParam); } } // so the input of custom node has format // input_var_name : type if (parameters != null && parameters.Count() > inputReceiverData) { var typeName = parameters[inputReceiverData].DisplayTypeName; if (!string.IsNullOrEmpty(typeName)) { node.InputSymbol += " : " + typeName; } } node.SetNameFromNodeNameAttribute(); node.Y = inputIndex * (50 + node.Height); uniqueInputSenders[key] = node; newNodes.Add(node); } ConnectorModel.Make(node, inputReceiverNode, 0, inputReceiverData); } #endregion #region Process outputs //List of all inner nodes to connect an output. Unique. var outportList = new List <Tuple <NodeModel, int> >(); var outConnectors = new List <Tuple <NodeModel, int, int> >(); int i = 0; if (outputs.Any()) { foreach (var output in outputs) { if (outportList.All(x => !(x.Item1 == output.Item1 && x.Item2 == output.Item2))) { NodeModel outputSenderNode = output.Item1; int outputSenderData = output.Item2; outportList.Add(Tuple.Create(outputSenderNode, outputSenderData)); //Create Symbol Node var node = new Output { Symbol = outputSenderNode.OutPorts[outputSenderData].Name, X = rightMost + 75 - leftShift }; node.Y = i * (50 + node.Height); node.SetNameFromNodeNameAttribute(); newNodes.Add(node); ConnectorModel.Make(outputSenderNode, node, outputSenderData, 0); i++; } } //Connect outputs to new node outConnectors.AddRange( from output in outputs let outputSenderNode = output.Item1 let outputSenderData = output.Item2 let outputReceiverData = output.Item3.Item1 let outputReceiverNode = output.Item3.Item2 select Tuple.Create( outputReceiverNode, outportList.FindIndex( x => x.Item1 == outputSenderNode && x.Item2 == outputSenderData), outputReceiverData)); } else { foreach (var hanging in selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.OutPorts.Count) .Where(index => !node.OutPorts[index].IsConnected) .Select(port => new { node, port })).Distinct()) { //Create Symbol Node var node = new Output { Symbol = hanging.node.OutPorts[hanging.port].Name, X = rightMost + 75 - leftShift }; node.Y = i * (50 + node.Height); node.SetNameFromNodeNameAttribute(); newNodes.Add(node); ConnectorModel.Make(hanging.node, node, hanging.port, 0); i++; } } #endregion var newId = Guid.NewGuid(); newWorkspace = new CustomNodeWorkspaceModel( nodeFactory, newNodes, newNotes, newAnnotations, Enumerable.Empty <PresetModel>(), currentWorkspace.ElementResolver, new WorkspaceInfo() { X = 0, Y = 0, Name = args.Name, Category = args.Category, Description = args.Description, ID = newId.ToString(), FileName = string.Empty, IsVisibleInDynamoLibrary = true }); newWorkspace.HasUnsavedChanges = true; RegisterCustomNodeWorkspace(newWorkspace); Debug.WriteLine("Collapsed workspace has {0} nodes and {1} connectors", newWorkspace.Nodes.Count(), newWorkspace.Connectors.Count()); var collapsedNode = CreateCustomNodeInstance(newId); collapsedNode.X = avgX; collapsedNode.Y = avgY; currentWorkspace.AddAndRegisterNode(collapsedNode, centered: false); undoRecorder.RecordCreationForUndo(collapsedNode); foreach (var connector in inConnectors.Select((x, idx) => new { node = x.Item1, from = x.Item2, to = idx }) .Select( nodeTuple => ConnectorModel.Make( nodeTuple.node, collapsedNode, nodeTuple.@from, nodeTuple.to)) .Where(connector => connector != null)) { undoRecorder.RecordCreationForUndo(connector); } foreach (var connector in outConnectors.Select( nodeTuple => ConnectorModel.Make( collapsedNode, nodeTuple.Item1, nodeTuple.Item2, nodeTuple.Item3)).Where(connector => connector != null)) { undoRecorder.RecordCreationForUndo(connector); } } return(newWorkspace); }
/// <summary> /// Checks whether the given connection is inside the node to code set or outside it. /// This determines if it should be redrawn(if it is external) or if it should be /// deleted (if it is internal) /// </summary> private static bool IsInternalNodeToCodeConnection(IEnumerable <NodeModel> nodes, ConnectorModel connector) { return(nodes.Contains(connector.Start.Owner) && nodes.Contains(connector.End.Owner)); }
void Connectors_ConnectorAdded(ConnectorModel c) { var viewModel = new ConnectorViewModel(this, c); if (_connectors.All(x => x.ConnectorModel != c)) _connectors.Add(viewModel); }
protected virtual void OnConnectorDeleted(ConnectorModel obj) { if (hasNodeInSyncWithDefinition) { undoRecorder.RecordModelAsOffTrack(obj.GUID); } var handler = ConnectorDeleted; if (handler != null) handler(obj); //Check if the workspace is loaded, i.e all the nodes are //added to the workspace. In that case, compute the Upstream cache for the //given node. if (workspaceLoaded) { obj.End.Owner.ComputeUpstreamOnDownstreamNodes(); } }
protected virtual void OnConnectorAdded(ConnectorModel obj) { RegisterConnector(obj); var handler = ConnectorAdded; if (handler != null) handler(obj); //Check if the workspace is loaded, i.e all the nodes are //added to the workspace. In that case, compute the Upstream cache for the //given node. if (workspaceLoaded) { obj.End.Owner.ComputeUpstreamOnDownstreamNodes(); } }
public void AddPresetShouldSetDirtyFlag() { var model = CurrentDynamoModel; //create some numbers var numberNode1 = new DoubleInput(); numberNode1.Value = "1"; var numberNode2 = new DoubleInput(); numberNode2.Value = "2"; var addNode = new DSFunction(model.LibraryServices.GetFunctionDescriptor("+")); //Check for Dirty flag Assert.AreEqual(model.CurrentWorkspace.HasUnsavedChanges, false); //add the nodes model.CurrentWorkspace.AddAndRegisterNode(numberNode1, false); model.CurrentWorkspace.AddAndRegisterNode(numberNode2, false); model.CurrentWorkspace.AddAndRegisterNode(addNode, false); //Check for Dirty flag Assert.AreEqual(model.CurrentWorkspace.HasUnsavedChanges, true); //Set the dirty flag to false. Mocking the save. model.CurrentWorkspace.HasUnsavedChanges = false; Assert.AreEqual(model.CurrentWorkspace.HasUnsavedChanges, false); //connect them up ConnectorModel.Make(numberNode1, addNode, 0, 0); ConnectorModel.Make(numberNode2, addNode, 0, 1); //Check for Dirty flag - After the connection the dirty flag should be set. Assert.AreEqual(model.CurrentWorkspace.HasUnsavedChanges, true); //Set the dirty flag to false. Mocking the save. model.CurrentWorkspace.HasUnsavedChanges = false; Assert.AreEqual(model.CurrentWorkspace.HasUnsavedChanges, false); Assert.AreEqual(model.CurrentWorkspace.Nodes.Count(), 3); Assert.AreEqual(model.CurrentWorkspace.Connectors.Count(), 2); //create the first state with the numbers selected DynamoSelection.Instance.Selection.Add(numberNode1); DynamoSelection.Instance.Selection.Add(numberNode2); var ids = DynamoSelection.Instance.Selection.OfType <NodeModel>().Select(x => x.GUID).ToList(); //create the preset from 2 nodes model.CurrentWorkspace.AddPreset( "state1", "3", ids); Assert.AreEqual(1, model.CurrentWorkspace.Presets.Count()); //change values numberNode1.Value = "2"; numberNode2.Value = "3"; DynamoSelection.Instance.ClearSelection(); DynamoSelection.Instance.Selection.Add(numberNode1); DynamoSelection.Instance.Selection.Add(numberNode2); ids = DynamoSelection.Instance.Selection.OfType <NodeModel>().Select(x => x.GUID).ToList(); model.CurrentWorkspace.AddPreset( "state2", "5", ids); //Check for Dirty flag - After the Preset the dirty flag should be set. Assert.AreEqual(model.CurrentWorkspace.HasUnsavedChanges, true); }
protected override void PortConnectedHandler(PortModel arg1, ConnectorModel arg2) { UpdateUpstream(); }
/// <summary> /// Collapse a set of nodes in a given workspace. Has the side effects of prompting the user /// first in order to obtain the name and category for the new node, /// writes the function to a dyf file, adds it to the FunctionDict, adds it to search, and compiles and /// places the newly created symbol (defining a lambda) in the Controller's FScheme Environment. /// </summary> /// <param name="selectedNodes"> The function definition for the user-defined node </param> /// <param name="currentWorkspace"> The workspace where</param> public static void Collapse(IEnumerable <NodeModel> selectedNodes, WorkspaceModel currentWorkspace, FunctionNamePromptEventArgs args = null) { var selectedNodeSet = new HashSet <NodeModel>(selectedNodes); if (args == null || !args.Success) { args = new FunctionNamePromptEventArgs(); dynSettings.Controller.DynamoModel.OnRequestsFunctionNamePrompt(null, args); //if (!dynSettings.Controller.DynamoViewModel.ShowNewFunctionDialog(ref newNodeName, ref newNodeCategory)) if (!args.Success) { return; } } var newNodeWorkspace = new CustomNodeWorkspaceModel(args.Name, args.Category, args.Description, 0, 0) { WatchChanges = false, HasUnsavedChanges = true }; var newNodeDefinition = new FunctionDefinition(Guid.NewGuid()) { WorkspaceModel = newNodeWorkspace }; currentWorkspace.DisableReporting(); #region Determine Inputs and Outputs //Step 1: determine which nodes will be inputs to the new node var inputs = new HashSet <Tuple <NodeModel, int, Tuple <int, NodeModel> > >( selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.InPortData.Count).Where(node.HasConnectedInput) .Select(data => Tuple.Create(node, data, node.Inputs[data])) .Where(input => !selectedNodeSet.Contains(input.Item3.Item2)))); var outputs = new HashSet <Tuple <NodeModel, int, Tuple <int, NodeModel> > >( selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.OutPortData.Count).Where(node.HasOutput).SelectMany( data => node.Outputs[data] .Where(output => !selectedNodeSet.Contains(output.Item2)) .Select(output => Tuple.Create(node, data, output))))); #endregion #region Detect 1-node holes (higher-order function extraction) var curriedNodeArgs = new HashSet <NodeModel>( inputs .Select(x => x.Item3.Item2) .Intersect(outputs.Select(x => x.Item3.Item2))) .Select( outerNode => { var node = new Apply1(); //MVVM : Don't make direct reference to view here //MVVM: no reference to view here //dynNodeView nodeUI = node.NodeUI; var elNameAttrib = node.GetType().GetCustomAttributes(typeof(NodeNameAttribute), true)[0] as NodeNameAttribute; if (elNameAttrib != null) { node.NickName = elNameAttrib.Name; } node.GUID = Guid.NewGuid(); //store the element in the elements list newNodeWorkspace.Nodes.Add(node); node.WorkSpace = newNodeWorkspace; node.DisableReporting(); //MVVM : Can't set view location here //dynSettings.Bench.WorkBench.Children.Add(nodeUI); //Place it in an appropriate spot //Canvas.SetLeft(nodeUI, Canvas.GetLeft(outerNode.NodeUI)); //Canvas.SetTop(nodeUI, Canvas.GetTop(outerNode.NodeUI)); node.X = outerNode.X; node.Y = outerNode.Y; //Fetch all input ports // in order // that have inputs // and whose input comes from an inner node List <int> inPortsConnected = Enumerable.Range(0, outerNode.InPortData.Count) .Where( x => outerNode.HasInput(x) && selectedNodeSet.Contains( outerNode.Inputs[x].Item2)) .ToList(); var nodeInputs = outputs .Where(output => output.Item3.Item2 == outerNode) .Select( output => new { InnerNodeInputSender = output.Item1, OuterNodeInPortData = output.Item3.Item1 }).ToList(); nodeInputs.ForEach(_ => node.AddInput()); node.RegisterAllPorts(); return(new { OuterNode = outerNode, InnerNode = node, Outputs = inputs.Where(input => input.Item3.Item2 == outerNode) .Select(input => input.Item3.Item1), Inputs = nodeInputs, OuterNodePortDataList = inPortsConnected }); }).ToList(); #endregion #region UI Positioning Calculations double avgX = selectedNodeSet.Average(node => node.X); double avgY = selectedNodeSet.Average(node => node.Y); double leftMost = selectedNodeSet.Min(node => node.X); double topMost = selectedNodeSet.Min(node => node.Y); double rightMost = selectedNodeSet.Max(node => node.X + node.Width); #endregion #region Move selection to new workspace var connectors = new HashSet <ConnectorModel>(currentWorkspace.Connectors.Where( conn => selectedNodeSet.Contains(conn.Start.Owner) && selectedNodeSet.Contains(conn.End.Owner))); //Step 2: move all nodes to new workspace // remove from old foreach (var ele in selectedNodeSet) { ele.SaveResult = false; currentWorkspace.Nodes.Remove(ele); ele.WorkSpace = newNodeWorkspace; } foreach (var ele in connectors) { currentWorkspace.Connectors.Remove(ele); } // add to new newNodeWorkspace.Nodes.AddRange(selectedNodeSet); newNodeWorkspace.Connectors.AddRange(connectors); double leftShift = leftMost - 250; foreach (NodeModel node in newNodeWorkspace.Nodes) { node.X = node.X - leftShift; node.Y = node.Y - topMost; } #endregion #region Insert new node into the current workspace //Step 5: insert new node into original workspace //var collapsedNode = dynSettings.Controller.DynamoViewModel.CreateFunction( // inputs.Select(x => x.Item1.InPortData[x.Item2].NickName), // outputs // .Where(x => !curriedNodeArgs.Any(y => y.OuterNode == x.Item3.Item2)) // .Select(x => x.Item1.OutPortData[x.Item2].NickName), // newNodeDefinition); //collapsedNode.GUID = Guid.NewGuid(); //currentWorkspace.Nodes.Add(collapsedNode); //collapsedNode.WorkSpace = currentWorkspace; //collapsedNode.X = avgX; //collapsedNode.Y = avgY; #endregion #region Destroy all hanging connectors //Step 6: connect inputs and outputs var removeConnectors = currentWorkspace.Connectors.Where(c => selectedNodeSet.Contains(c.Start.Owner) || selectedNodeSet.Contains(c.End.Owner)) .ToList(); foreach (ConnectorModel connector in removeConnectors) { connector.NotifyConnectedPortsOfDeletion(); currentWorkspace.Connectors.Remove(connector); } #endregion newNodeWorkspace.Nodes.ToList().ForEach(x => x.DisableReporting()); var inConnectors = new List <Tuple <NodeModel, int, int> >(); #region Process inputs var uniqueInputSenders = new Dictionary <Tuple <NodeModel, int>, Symbol>(); //Step 3: insert variables (reference step 1) foreach (var input in Enumerable.Range(0, inputs.Count).Zip(inputs, Tuple.Create)) { int inputIndex = input.Item1; NodeModel inputReceiverNode = input.Item2.Item1; int inputReceiverData = input.Item2.Item2; NodeModel inputNode = input.Item2.Item3.Item2; int inputData = input.Item2.Item3.Item1; Symbol node; var key = Tuple.Create(inputNode, inputData); if (uniqueInputSenders.ContainsKey(key)) { node = uniqueInputSenders[key]; } else { //MVVM : replace NodeUI reference with node inConnectors.Add(Tuple.Create(inputNode, inputData, inputIndex)); //Create Symbol Node node = new Symbol { InputSymbol = inputReceiverNode.InPortData[inputReceiverData].NickName }; //MVVM : Don't make direct reference to view here //dynNodeView nodeUI = node.NodeUI; var elNameAttrib = node.GetType().GetCustomAttributes(typeof(NodeNameAttribute), true)[0] as NodeNameAttribute; if (elNameAttrib != null) { node.NickName = elNameAttrib.Name; } node.GUID = Guid.NewGuid(); //store the element in the elements list newNodeWorkspace.Nodes.Add(node); node.WorkSpace = newNodeWorkspace; node.DisableReporting(); node.X = 0; node.Y = inputIndex * (50 + node.Height); uniqueInputSenders[key] = node; } var curriedNode = curriedNodeArgs.FirstOrDefault(x => x.OuterNode == inputNode); if (curriedNode == null) { var conn1 = ConnectorModel.Make(node, inputReceiverNode, 0, inputReceiverData, PortType.INPUT); if (conn1 != null) { newNodeWorkspace.Connectors.Add(conn1); } } else { //Connect it to the applier var conn = ConnectorModel.Make(node, curriedNode.InnerNode, 0, 0, PortType.INPUT); if (conn != null) { newNodeWorkspace.Connectors.Add(conn); } //Connect applier to the inner input receive var conn2 = ConnectorModel.Make( curriedNode.InnerNode, inputReceiverNode, 0, inputReceiverData, PortType.INPUT); if (conn2 != null) { newNodeWorkspace.Connectors.Add(conn2); } } } #endregion #region Process outputs //List of all inner nodes to connect an output. Unique. var outportList = new List <Tuple <NodeModel, int> >(); var outConnectors = new List <Tuple <NodeModel, int, int> >(); int i = 0; foreach (var output in outputs) { if (outportList.All(x => !(x.Item1 == output.Item1 && x.Item2 == output.Item2))) { NodeModel outputSenderNode = output.Item1; int outputSenderData = output.Item2; NodeModel outputReceiverNode = output.Item3.Item2; if (curriedNodeArgs.Any(x => x.OuterNode == outputReceiverNode)) { continue; } outportList.Add(Tuple.Create(outputSenderNode, outputSenderData)); //Create Symbol Node var node = new Output { Symbol = outputSenderNode.OutPortData[outputSenderData].NickName }; //dynNodeView nodeUI = node.NodeUI; var elNameAttrib = node.GetType().GetCustomAttributes(typeof(NodeNameAttribute), false)[0] as NodeNameAttribute; if (elNameAttrib != null) { node.NickName = elNameAttrib.Name; } node.GUID = Guid.NewGuid(); //store the element in the elements list newNodeWorkspace.Nodes.Add(node); node.WorkSpace = newNodeWorkspace; node.DisableReporting(); node.X = rightMost + 75 - leftShift; node.Y = i * (50 + node.Height); var conn = ConnectorModel.Make( outputSenderNode, node, outputSenderData, 0, PortType.INPUT); if (conn != null) { newNodeWorkspace.Connectors.Add(conn); } i++; } } //Connect outputs to new node foreach (var output in outputs) { //Node to be connected to in CurrentWorkspace NodeModel outputSenderNode = output.Item1; //Port to be connected to on outPutNode_outer int outputSenderData = output.Item2; int outputReceiverData = output.Item3.Item1; NodeModel outputReceiverNode = output.Item3.Item2; var curriedNode = curriedNodeArgs.FirstOrDefault( x => x.OuterNode == outputReceiverNode); if (curriedNode == null) { // we create the connectors in the current space later //MVVM : replaced multiple dynNodeView refrences with dynNode outConnectors.Add( Tuple.Create( outputReceiverNode, outportList.FindIndex( x => x.Item1 == outputSenderNode && x.Item2 == outputSenderData), outputReceiverData)); } else { int targetPort = curriedNode.Inputs .First( x => x.InnerNodeInputSender == outputSenderNode) .OuterNodeInPortData; int targetPortIndex = curriedNode.OuterNodePortDataList.IndexOf(targetPort); //Connect it (new dynConnector) var conn = ConnectorModel.Make( outputSenderNode, curriedNode.InnerNode, outputSenderData, targetPortIndex + 1, PortType.INPUT); if (conn != null) { newNodeWorkspace.Connectors.Add(conn); } } } #endregion // save and load the definition from file newNodeDefinition.SyncWithWorkspace(true, true); dynSettings.Controller.DynamoModel.Workspaces.Add(newNodeWorkspace); string name = newNodeDefinition.FunctionId.ToString(); var collapsedNode = dynSettings.Controller.DynamoModel.CreateNode(avgX, avgY, name); // place the node as intended, not centered collapsedNode.X = avgX; collapsedNode.Y = avgY; collapsedNode.DisableReporting(); foreach (var nodeTuple in inConnectors) { var conn = ConnectorModel.Make( nodeTuple.Item1, collapsedNode, nodeTuple.Item2, nodeTuple.Item3, PortType.INPUT); if (conn != null) { currentWorkspace.Connectors.Add(conn); } } foreach (var nodeTuple in outConnectors) { var conn = ConnectorModel.Make( collapsedNode, nodeTuple.Item1, nodeTuple.Item2, nodeTuple.Item3, PortType.INPUT); if (conn != null) { currentWorkspace.Connectors.Add(conn); } } collapsedNode.EnableReporting(); currentWorkspace.EnableReporting(); newNodeWorkspace.WatchChanges = true; }