示例#1
0
        public void CanSavePinState()
        {
            var model = CurrentDynamoModel;
            var cbn = new CodeBlockNodeModel(model.LibraryServices);
            var command = new DynamoModel.CreateNodeCommand(cbn, 0, 0, true, false);

            CurrentDynamoModel.ExecuteCommand(command);

            UpdateCodeBlockNodeContent(cbn, "42");
            cbn.PreviewPinned = true;

            DynamoSelection.Instance.Selection.Add(cbn);
            var ids = DynamoSelection.Instance.Selection.OfType<NodeModel>().Select(x => x.GUID).ToList();
            model.ExecuteCommand(new DynamoModel.AddPresetCommand("state1", "3", ids));

            UpdateCodeBlockNodeContent(cbn, "146");
            DynamoSelection.Instance.Selection.Remove(cbn);

            model.CurrentWorkspace.ApplyPreset(model.CurrentWorkspace.Presets.Where(
               x => x.Name == "state1").First());

            RunCurrentModel();

            Assert.IsTrue(cbn.PreviewPinned);
        }
示例#2
0
        /// <summary>
        /// Create code block editor by the view of code block node.
        /// </summary>
        /// <param name="nodeView"></param>
        public CodeBlockEditor(NodeView nodeView): base(nodeView)
        {
            this.codeBlockNode = nodeViewModel.NodeModel as CodeBlockNodeModel;
            if (codeBlockNode == 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(codeBlockNode.Code);

            // the code block should not be in focus upon undo/redo actions on node
            if (codeBlockNode.ShouldFocus)
            {
                Loaded += (obj, args) => SetFocus(); 
            }

            WatermarkLabel.Text = Properties.Resources.WatermarkLabelText;
        }
示例#3
0
        /// <summary>
        ///     Paste ISelectable objects from the clipboard to the workspace at specified point.
        /// </summary>
        /// <param name="targetPoint">Location where data will be pasted</param>
        /// <param name="useOffset">Indicates whether we will use current workspace offset or paste nodes
        /// directly in this point. </param>
        public void Paste(Point2D targetPoint, bool useOffset = true)
        {
            if (useOffset)
            {
                // Provide a small offset when pasting so duplicate pastes aren't directly on top of each other
                CurrentWorkspace.IncrementPasteOffset();
            }

            //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>();

            // 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);
            }

            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) && !(node is Symbol) && !(node is Output))
                    newNode.NickName = node.NickName;

                newNode.Width = node.Width;
                newNode.Height = node.Height;

                modelLookup.Add(node.GUID, newNode);

                newNodeModels.Add(newNode);
            }

            var newItems = newNodeModels.Concat<ModelBase>(newNoteModels);

            var shiftX = targetPoint.X - newItems.Min(item => item.X);
            var shiftY = targetPoint.Y - newItems.Min(item => item.Y);
            var offset = useOffset ? CurrentWorkspace.CurrentPasteOffset : 0;

            foreach (var model in newItems)
            {
                model.X = model.X + shiftX + offset;
                model.Y = model.Y + shiftY + offset;
            }

            // Add the new NodeModel's to the Workspace
            foreach (var newNode in newNodeModels)
            {
                CurrentWorkspace.AddAndRegisterNode(newNode, false);
                createdModels.Add(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);
            }

            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>();
                // some models can be deleted after copying them,
                // so they need to be in pasted annotation as well
                var modelsToRestore = annotation.DeletedModelBases.Intersect(ClipBoard);
                var modelsToAdd = annotation.SelectedModels.Concat(modelsToRestore);
                // checked condition here that supports pasting of multiple groups
                foreach (var models in modelsToAdd)
                {
                    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);
            }

            // adding an annotation overrides selection, so add nodes and notes after
            foreach (var item in newItems)
            {
                AddToSelection(item);
            }

            // Record models that are created as part of the command.
            CurrentWorkspace.RecordCreatedModels(createdModels);
        }
示例#4
0
        /// <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;
        }
示例#5
0
        /// <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;
        }
示例#6
0
        internal void ConvertNodesToCodeInternal(EngineController engineController, INamingProvider namingProvider)
        {
            var selectedNodes = DynamoSelection.Instance
                                               .Selection
                                               .OfType<NodeModel>()
                                               .Where(n => n.IsConvertible);
            if (!selectedNodes.Any())
                return;

            var cliques = NodeToCodeCompiler.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, namingProvider);

                    #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);
                        RemoveNode(node);
                        #endregion
                    }
                    #endregion

                    #region Step II. Create the new code block node
                    var outputVariables = externalOutputConnections.Values;
                    var newResult = NodeToCodeCompiler.ConstantPropagationForTemp(nodeToCodeResult, outputVariables);

                    // Rewrite the AST using the shortest unique name in case of namespace conflicts
                    NodeToCodeCompiler.ReplaceWithShortestQualifiedName(
                        engineController.LibraryServices.LibraryManagementCore.ClassTable, newResult.AstNodes, ElementResolver);
                    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, ElementResolver);
                    undoHelper.RecordCreation(codeBlockNode);
                   
                    AddAndRegisterNode(codeBlockNode, false);
                    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();
        }
示例#7
0
 /// <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);
 }
示例#8
0
        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;
        }
示例#9
0
 private void UpdateCodeBlockNodeContent(CodeBlockNodeModel cbn, string value)
 {
     var command = new DynCmd.UpdateModelValueCommand(Guid.Empty, cbn.GUID, "Code", value);
     CurrentDynamoModel.ExecuteCommand(command);
 }
示例#10
0
            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;
            }
示例#11
0
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            NodeModel node = null;

            var obj = JObject.Load(reader);
            var type = Type.GetType(obj["$type"].Value<string>());
            
            var guid = Guid.Parse(obj["Uuid"].Value<string>());
            var displayName = obj["DisplayName"].Value<string>();
            //var x = obj["X"].Value<double>();
            //var y = obj["Y"].Value<double>();

            var inPorts = obj["InputPorts"].ToArray().Select(t => t.ToObject<PortModel>()).ToArray();
            var outPorts = obj["OutputPorts"].ToArray().Select(t => t.ToObject<PortModel>()).ToArray();

            var resolver = (IdReferenceResolver)serializer.ReferenceResolver;

            if (type == typeof(Function))
            {
                var functionId = Guid.Parse(obj["FunctionUuid"].Value<string>());
                node = manager.CreateCustomNodeInstance(functionId);
                RemapPorts(node, inPorts, outPorts, resolver);
            }
            else if(type == typeof(CodeBlockNodeModel))
            {
                var code = obj["Code"].Value<string>();
                node = new CodeBlockNodeModel(code, guid, 0.0, 0.0, libraryServices, ElementResolver);
                RemapPorts(node, inPorts, outPorts, resolver);
            }
            else if(typeof(DSFunctionBase).IsAssignableFrom(type))
            {
                var mangledName = obj["FunctionName"].Value<string>();

                var description = libraryServices.GetFunctionDescriptor(mangledName);

                if(type == typeof(DSVarArgFunction))
                {
                    node = new DSVarArgFunction(description);
                    // The node syncs with the function definition.
                    // Then we need to make the inport count correct
                    var varg = (DSVarArgFunction)node;
                    varg.VarInputController.SetNumInputs(inPorts.Count());
                }
                else if(type == typeof(DSFunction))
                {
                    node = new DSFunction(description);
                    
                }
                RemapPorts(node, inPorts, outPorts, resolver);
            }
            else if (type == typeof(DSVarArgFunction))
            {
                var functionId = Guid.Parse(obj["FunctionUuid"].Value<string>());
                node = manager.CreateCustomNodeInstance(functionId);
                RemapPorts(node, inPorts, outPorts, resolver);
            }
            else
            {
                node = (NodeModel)obj.ToObject(type);
            }

            node.GUID = guid;
            node.NickName = displayName;
            //node.X = x;
            //node.Y = y;

            // Add references to the node and the ports to the reference resolver,
            // so that they are available for entities which are deserialized later.
            serializer.ReferenceResolver.AddReference(serializer.Context, node.GUID.ToString(), node);

            foreach(var p in node.InPorts)
            {
                serializer.ReferenceResolver.AddReference(serializer.Context, p.GUID.ToString(), p);
            }
            foreach (var p in node.OutPorts)
            {
                serializer.ReferenceResolver.AddReference(serializer.Context, p.GUID.ToString(), p);
            }
            return node;
        }
示例#12
0
        public void PreviewBubble_CodeBlockIsNotInFocus()
        {
            var code = new CodeBlockNodeModel(this.Model.LibraryServices);

            Model.AddNodeToCurrentWorkspace(code, true);
            Run();

            // Click on DragCanvas.
            View.ChildOfType<DragCanvas>().RaiseEvent(
                new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left)
            {
                RoutedEvent = Mouse.MouseDownEvent
            });
            var nodeView = NodeViewWithGuid(code.GUID.ToString());
            Assert.IsNotNull(nodeView);

            // Move mouse on code node.
            var dispatcherOperation = View.Dispatcher.BeginInvoke(new Action(
            () =>
            {
                nodeView.RaiseEvent(
                    new MouseEventArgs(Mouse.PrimaryDevice, 0) { RoutedEvent = Mouse.MouseEnterEvent });
            }));
            DispatcherUtil.DoEvents();

            dispatcherOperation.Completed += (s, args) =>
                Assert.IsTrue(nodeView.PreviewControl.IsCondensed);

            // Move mouse on code node preview.
            dispatcherOperation = View.Dispatcher.BeginInvoke(new Action(
            () =>
            {
                nodeView.PreviewControl.RaiseEvent(
                    new MouseEventArgs(Mouse.PrimaryDevice, 0) { RoutedEvent = Mouse.MouseEnterEvent });
            }));
            DispatcherUtil.DoEvents();

            dispatcherOperation.Completed += (s, args) =>
            Assert.IsTrue(nodeView.PreviewControl.IsExpanded);
        }
示例#13
0
        public void PreviewBubble_NoCrashWithCodeBlock()
        {
            var code = new CodeBlockNodeModel(this.Model.LibraryServices);

            this.Model.AddNodeToCurrentWorkspace(code, true);
            this.Run();
            var nodeView = NodeViewWithGuid(code.GUID.ToString());
            
            Assert.IsNotNull(nodeView);
            View.Dispatcher.Invoke(() =>
            {
                nodeView.RaiseEvent(new MouseEventArgs(Mouse.PrimaryDevice, 0) 
                { RoutedEvent = Mouse.MouseEnterEvent });
                nodeView.PreviewControl.RaiseEvent(new MouseEventArgs(Mouse.PrimaryDevice, 0)
                { RoutedEvent = Mouse.MouseEnterEvent });
            });
            DispatcherUtil.DoEvents();

            Assert.IsTrue(nodeView.PreviewControl.IsHidden);
        }