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