public void TestSynchronizeToLifeRunnerOperationException()
        {
            GraphController graphController= new GraphController(null);

            Assert.Throws<InvalidOperationException>(() =>
            {
                DeltaNodes deltaNodes = new DeltaNodes();
                graphController.SynchronizeToLiveRunner(deltaNodes);
            });
        }
        internal GraphController(IGraphVisualHost visualHost, string filePath)
        {
            if (!File.Exists(filePath))
                throw new ArgumentException("'filePath' is not a valid path");

            this.FileLoadInProgress = true;
            this.InitializeInternal(visualHost);
            this.LoadFileInternal(filePath);
            this.filePath = filePath;

            try
            {
                // Attempt to see if we are creating the graph controller from recovery file.
                int index = -1; uint graphId = uint.MaxValue;
                Utilities.GetBackupFileIndex(this.filePath, ref graphId, ref index);

                // If we reach here without exception, then "filePath" is a backup file
                // name. In which case we should not assign a name to "this.filePath" so
                // that the user will be prompted to supply an alternative file name.
                //
                this.filePath = string.Empty;
            }
            catch (Exception)
            {
            }

            DeltaNodes deltaNodes = new DeltaNodes();
            deltaNodes.AppendToAddedNodes(this.nodeCollection.Values.ToList<IVisualNode>());
            this.ValidateNodesSyntax(deltaNodes.AddedNodes);
            this.ValidateDefinedAndReferencedVariables();
            this.UpdateDirtyNodes();
            edgeController.AuditEdges();
            this.edgeController.UpdateDirtyEdges(null);
            if (this.nodeCollection.Count > 0)
                this.SynchronizeToLiveRunner(deltaNodes);
            this.FileLoadInProgress = false;
        }
示例#3
0
        internal bool Undo(DeltaNodes deltaNodes)
        {
            if (this.ActionCount != -1)
                throw new InvalidOperationException("EndGroup() function was not called");

            //Check if undoStorage is empty
            if (this.undoStorage.GetPosition() <= 0)
                return false;

            //Retrieve number of UserActions in the group
            this.undoStorage.Seek(-12, SeekOrigin.Current);
            int numOfActions = this.undoStorage.ReadInteger(FieldCode.ActionCount);
            this.undoStorage.Seek(-12, SeekOrigin.Current);

            //Loop according to the number of UserAction
            for (int i = 1; i <= numOfActions; i++)
            {
                //Retrieve the start point of the data and UserAction type
                this.undoStorage.Seek(-28, SeekOrigin.Current);
                long shift = this.undoStorage.ReadLong(FieldCode.Shift);
                UserAction userAction = (UserAction)this.undoStorage.ReadInteger(FieldCode.UserAction);
                this.undoStorage.Seek(-(shift + 28), SeekOrigin.Current);

                //Undo previous task accordingly
                switch (userAction)
                {
                    case UserAction.RuntimeStates:
                        //1. Retrieve the current runtimeStates and store the current runtimeStates in the redoStorage
                        //2. Update the runtimeStates through deserialization from the undoStorage
                        this.RecordRuntimeStates(this.redoStorage, this.graphController.GetRuntimeStates(), UserAction.RuntimeStates);
                        this.UpdateRuntimeStates(this.undoStorage, this.graphController.GetRuntimeStates());
                        break;

                    case UserAction.EdgeCreation:
                        //1. Retrieve edgeId from undoStorage and find the corresponding edge from the dictionary
                        //2. Store the corresponding edge in the redoStorage
                        //3. Delete corresponding edge in dictionary
                        List<IVisualEdge> edgeListForCreation = this.RetrieveEdgesFromIdsInStorage(this.undoStorage);
                        this.RecordEdges(this.redoStorage, edgeListForCreation, UserAction.EdgeCreation);
                        this.DeleteEdges(edgeListForCreation);
                        break;

                    case UserAction.EdgeDeletion:
                        //1. Retrieve the edge from undoStorage
                        //2. Store the corresponding edgeId in the redoStorage
                        //3. Add the corresponding edge to the dictionary
                        List<IVisualEdge> edgeListForDeletion = this.RetrieveEdgesFromStorage(this.undoStorage);
                        this.RecordEdgeIds(this.redoStorage, edgeListForDeletion, UserAction.EdgeDeletion);
                        this.AddEdges(edgeListForDeletion);
                        break;

                    case UserAction.EdgeModification:
                        //1. Retrieve the edgeId from undoStorage without creating the entire edge
                        //2. Retrieve the corresponding edge in the dictionary
                        //3. Store the corresponding edge in the redoStorage
                        //4. Reset cursor position in stream to start of first header, ie. -shift value
                        //5. Update the corresponding edge in the dictionary through deserialization from
                        //   from the undoStorage
                        List<uint> edgeIdList = this.RetrieveEdgeIdsFromStorage(this.undoStorage);
                        List<IVisualEdge> edgeList = this.RetrieveEdgesFromDictionary(edgeIdList);
                        this.RecordEdges(this.redoStorage, edgeList, UserAction.EdgeModification);
                        this.undoStorage.Seek(-shift, SeekOrigin.Current);
                        this.UpdateEdges(this.undoStorage, edgeList);
                        break;

                    case UserAction.NodeCreation:
                        //1. Retrieve nodeId from undoStorage and find the corresponding node from the dictionary
                        //2. Store the corresponding node and slot in the redoStorage
                        //3. Delete corresponding node and slot in dictionary
                        //4. Record the deleted node for LifeRunner
                        List<IVisualNode> nodeListForCreation = this.RetrieveNodesFromIdsInStorage(this.undoStorage);
                        this.RecordNodesAndSlots(this.redoStorage, nodeListForCreation, UserAction.NodeCreation);
                        this.DeleteNodesAndSlots(nodeListForCreation);
                        deltaNodes.AppendToRemovedNodes(nodeListForCreation);
                        break;

                    case UserAction.NodeDeletion:
                        //1. Retrieve the slot from undoStorage
                        //2. Retrieve the node from undoStorage
                        //3. Store the corresponding nodeId in the redoStorage
                        //4. Add the corresponding node and slot to the dictionary
                        //5. Record the added node for LifeRunner
                        List<ISlot> slotListForDeletion = this.RetrieveSlotsFromStorage(this.undoStorage);
                        List<IVisualNode> nodeListForDeletion = this.RetrieveNodesFromStorage(this.undoStorage);
                        this.RecordNodeIds(this.redoStorage, nodeListForDeletion, UserAction.NodeDeletion);
                        this.AddNodesAndSlots(nodeListForDeletion, slotListForDeletion);
                        deltaNodes.AppendToAddedNodes(nodeListForDeletion);
                        break;

                    case UserAction.NodeModification:
                        //1. Retrieve the slotId from undoStorage without creating the entire slot
                        //2. Retrieve the nodeId from undoStorage without creating the entire node
                        //3. Retrieve the corresponding node in the dictionary
                        //4. Store the corresponding node and slot in the redoStorage
                        //5. Resolve, if any, the extra number of slot after undo
                        //6. Reset cursor position in stream to start of first header, ie, -shift value
                        //7. Update the corresponding node and slot in the dictionary through deserialization
                        //   from the undoStorage and resolve, if any, the missing slot after undo
                        //8. Record the modified node for LifeRunner
                        List<uint> slotIdList = this.RetrieveSlotIdsFromStorage(this.undoStorage);
                        List<uint> nodeIdList = this.RetrieveNodeIdsFromStorage(this.undoStorage);
                        List<IVisualNode> nodeList = this.RetrieveNodesFromDictionary(nodeIdList);
                        this.RecordNodesAndSlots(this.redoStorage, nodeList, UserAction.NodeModification);
                        this.ResolveExtraNumberOfSlotsAfterAction(nodeList, slotIdList);
                        this.undoStorage.Seek(-shift, SeekOrigin.Current);
                        this.UpdateNodesAndSlostWithResolveMissingSlotAfterAction(this.undoStorage, nodeList, slotIdList);
                        deltaNodes.AppendToModifiedNodes(nodeList);
                        break;

                    default:
                        throw new InvalidOperationException("Unknown UserAction");
                }

                //Set cursor for next undo
                this.undoStorage.Seek(-shift, SeekOrigin.Current);
            }

            //Upon Success
            this.redoStorage.WriteInteger(FieldCode.ActionCount, numOfActions);
            return true;
        }
        public bool ProcessNodesToCodeConversion(List<uint> originalNodeIds, List<SnapshotNode> snapshotNodes)
        {
            if (originalNodeIds == null || originalNodeIds.Count == 0 || snapshotNodes == null || snapshotNodes.Count == 0)
                return false;

            undoRedoRecorder.BeginGroup();
            undoRedoRecorder.RecordRuntimeStatesForUndo(graphProperties.RuntimeStates);

            List<IVisualNode> originalNodes = GetNodesByIds(originalNodeIds);
            List<IVisualNode> modifiedNodes = new List<IVisualNode>();
            DeleteNodesWithRecord(originalNodes, out modifiedNodes);

            List<Connection> inputConnections = null;
            Dictionary<string, string> identifierTempVariableMap = null;
            List<VisualNode> identifierNodes = CreateIntermediateIdentifierNodes(snapshotNodes, out inputConnections, out identifierTempVariableMap);
            ReplaceVariableNamesInSnapshotNodes(identifierTempVariableMap, snapshotNodes);
            List<VisualNode> codeBlockNodes = CreateVisualNodesFromSnapshotNodes(snapshotNodes);

            List<IVisualNode> createdNodes = new List<IVisualNode>();
            createdNodes.AddRange(identifierNodes);
            createdNodes.AddRange(codeBlockNodes);

            SetNodesPosition(createdNodes, originalNodes[0].X, originalNodes[0].Y);

            Dictionary<VisualNode, List<Connection>> outputNodeConnectionMap = GetNodeOutputConnectionMapFromSnapshotNodes(snapshotNodes, codeBlockNodes);
            Dictionary<VisualNode, List<Connection>> inputNodeConnectionMap = GetNodeInputConnectionMapFromSnapshotNodes(identifierNodes, inputConnections);
            EstablishExplicitConnections(inputNodeConnectionMap, outputNodeConnectionMap, modifiedNodes);

            EstablishImplicitConnections(modifiedNodes);
            undoRedoRecorder.EndGroup();

            ValidateDefinedAndReferencedVariables();
            BeautifyCode(codeBlockNodes);
            UpdateSlotsVisiblity();
            selectionBox.UpdateSelectionBox(GetSelectedNodes());
            UpdateDirtyNodes();
            edgeController.UpdateDirtyEdges(createdNodes);

            //update delta nodes send to liveRunner
            DeltaNodes deltaNodes = new DeltaNodes();
            deltaNodes.AppendToAddedNodes(createdNodes);
            deltaNodes.AppendToModifiedNodes(modifiedNodes.Distinct().ToList());
            deltaNodes.AppendToRemovedNodes(originalNodes);
            SynchronizeToLiveRunner(deltaNodes);
            return true;
        }
        internal void SynchronizeToLiveRunner(DeltaNodes deltaNodes)
        {
            if (false != deltaNodes.IsEmpty)
                throw new InvalidOperationException("Nothing to send to 'lifeRunner'");

            // If there is something that we would like to query
            // the value for, add it into the modified node list.
            if (false == scheduledDeltaNodes.IsEmpty)
            {
                deltaNodes.AppendToRemovedNodes(scheduledDeltaNodes.RemovedNodes);
                deltaNodes.AppendToAddedNodes(scheduledDeltaNodes.AddedNodes);
                deltaNodes.AppendToModifiedNodes(scheduledDeltaNodes.ModifiedNodes);
                scheduledDeltaNodes.Reset();
            }

            // Compact the DeltaNodes so that there is no duplicate and no node
            // exists in more than one list (e.g. addedNodes and modifiedNodes).
            deltaNodes.Compact();

            SynchronizeData sd = new SynchronizeData();
            if (null != deltaNodes.RemovedNodes && (deltaNodes.RemovedNodes.Count > 0))
            {
                foreach (IVisualNode node in deltaNodes.RemovedNodes)
                    sd.RemovedNodes.Add(node.NodeId);
            }

            if (null != deltaNodes.AddedNodes && (deltaNodes.AddedNodes.Count > 0))
                sd.AddedNodes = this.CreateSnapshotNodesFromVisualNodes(deltaNodes.AddedNodes);
            if (null != deltaNodes.ModifiedNodes && (deltaNodes.ModifiedNodes.Count > 0))
                sd.ModifiedNodes = this.CreateSnapshotNodesFromVisualNodes(deltaNodes.ModifiedNodes);

            // Tell the graph compiler that some variables are undefined.
            MergeUndefinedVariablesIntoData(deltaNodes.Undefinitions, sd);

            this.sdc.sdList.Add(sd);
            if (Configurations.EnableLiveExection)
            {
                try
                {
                    this.CurrentSynchronizer.PushUpdate(sd);
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e);
                }
            }
        }
        public void TestUndo()
        {
            GraphController graphController = new GraphController(null);
            UndoRedoRecorder urr = new UndoRedoRecorder(graphController);

            DeltaNodes deltaNodes = new DeltaNodes();
            bool result = urr.Undo(deltaNodes);
            Assert.AreEqual(false, result);
        }
        private void CreateNodeInternal(VisualNode node, double x, double y)
        {
            if (null == node)
                throw new ArgumentNullException("node");

            if (CoreComponent.Instance.StudioSettings.SuppressPreview)
                node.SetNodeState(States.PreviewHidden);

            node.X = x;
            node.Y = y;
            node.Compose(); // Just to compute the dimension.

            DeltaNodes deltaNodes = new DeltaNodes();
            deltaNodes.AppendToAddedNodes(node);

            if (node.VisualType != NodeType.CodeBlock)
            {
                bool visualOnlyNode = (node.VisualType == NodeType.Condensed ||
                    (node.VisualType == NodeType.Render));

                this.undoRedoRecorder.BeginGroup();
                this.undoRedoRecorder.RecordRuntimeStatesForUndo(this.graphProperties.RuntimeStates);
                this.undoRedoRecorder.RecordNodeCreationForUndo(deltaNodes.AddedNodes);
                this.graphProperties.RuntimeStates.AddVariablesDefinedInNode(node, false);

                if (false == visualOnlyNode)
                {
                    List<IVisualNode> modifiedNodes = new List<IVisualNode>();
                    EstablishImplicitConnections(modifiedNodes);
                    deltaNodes.AppendToModifiedNodes(modifiedNodes);
                }

                this.undoRedoRecorder.EndGroup();

                if (false == visualOnlyNode)
                    this.SynchronizeToLiveRunner(deltaNodes);
            }

            this.UpdateDirtyNodes();
            node.PositionAtCenter(node.NodeId);
        }
        private void AddReplicationGuide(uint nodeId)
        {
            DeltaNodes deltaNodes = new DeltaNodes();
            IVisualNode node = this.GetVisualNode(nodeId);
            deltaNodes.AppendToModifiedNodes(node);

            this.undoRedoRecorder.BeginGroup();
            this.undoRedoRecorder.RecordNodeModificationForUndo(deltaNodes.ModifiedNodes);
            this.undoRedoRecorder.EndGroup();

            FunctionNode fNode = node as FunctionNode;
            fNode.AddReplicationGuides();
            fNode.Compose();

            //After executing AddReplicationGuides(), the node in nodeList would already be modified
            this.SynchronizeToLiveRunner(deltaNodes);
        }
        private void RecordAndDeleteNode(uint nodeId)
        {
            DeltaNodes deltaNodes = new DeltaNodes();
            deltaNodes.AppendToRemovedNodes(this.GetVisualNode(nodeId));
            deltaNodes.AppendToModifiedNodes(FindAssociatedNodesFromNodes(deltaNodes.RemovedNodes));

            this.undoRedoRecorder.BeginGroup();
            this.undoRedoRecorder.RecordRuntimeStatesForUndo(this.graphProperties.RuntimeStates);
            this.undoRedoRecorder.RecordNodeDeletionForUndo(deltaNodes.RemovedNodes);
            this.undoRedoRecorder.RecordNodeModificationForUndo(deltaNodes.ModifiedNodes);
            this.DeleteNodes(deltaNodes.RemovedNodes);
            this.undoRedoRecorder.EndGroup();

            this.ValidateDefinedAndReferencedVariables();
            this.UpdateSlotsVisiblity();
            this.SynchronizeToLiveRunner(deltaNodes);
        }