/// <summary> /// Redoes the last reverted variation, if any. /// Optionally indication of ability to undo and echo the executing command variation can be specified. /// </summary> public void Redo(bool CanUndo = true, bool Echo = true) { if (this.IsUndoing || this.IsRedoing) { Console.WriteLine("Cannot redo edit operation while already an undo/redo is being performed."); return; } if (!HasRedoableVariations) { if (Echo) { Console.WriteLine("Nothing to redo."); } return; } if (this.IsVariating) { Console.WriteLine("Cannot redo edit operation while a command variation is open (not yet completed or discarded)."); return; } // Takes the last operation this.CurrentExecutingCommand = this.RedoStack.Pop(); this.IsRedoing = true; if (Echo) { Console.WriteLine(this.CurrentExecutingCommand.CommandName); } // If undoable, initiates a command variation to capture the changes to be later undone. if (CanUndo) { this.StartCommandVariation(this.CurrentExecutingCommand.CommandName); } // Executes the redo this.CurrentExecutingCommand.Execute(this); // Saves the captured variation into the undo stack. if (CanUndo) { var InverseVariation = this.CompleteCommandVariation(); if (InverseVariation != null) { this.UndoStack.Push(InverseVariation); } } this.CurrentExecutingCommand = null; this.IsRedoing = false; }
/// <summary> /// Starts the declaration of a Command, which is stored as a group/combination of variations. /// This command declaration is temporarily stored until completed or discarded, thus allowing nesting. /// Optionally, it can be specified to alter the Existence-Status while variating. /// </summary> public CommandVariation StartCommandVariation(string AppliedCommand, bool AlterExistenceStatusWhileVariating = true) { //T Console.WriteLine("Command-INITIATED: " + AppliedCommand + " <<<<+++++++++++++++++++++++++++++ Command-Stack count=" + this.CommandCombiningStack.Count.ToString()); // Keep the nesting parent alteration of existente-status if (this.CommandCombiningStack.Count > 0 && !this.CommandCombiningStack.Peek().AlterExistenceStatusWhileVariating) { AlterExistenceStatusWhileVariating = false; } var Variation = new CommandVariation(AppliedCommand, AlterExistenceStatusWhileVariating); this.CommandCombiningStack.Push(Variation); return(Variation); }
/// <summary> /// Undoes the last applied variation, if any. /// Optionally indication of ability to redo (outside a nesting command) and echo the executing command variation can be specified. /// </summary> public void Undo(bool CanRedo = true, bool Echo = true) { if (this.IsUndoing || this.IsRedoing) { Console.WriteLine("Cannot undo edit operation while already an undo/redo is being performed."); return; } if (!HasUndoableVariations) { if (Echo) { Console.WriteLine("Nothing to undo."); } return; } // If inside a nesting command, the undo the last nested command if (this.IsVariating) { if (this.CommandCombiningStack.Count < 1 || !(this.CurrentVariatingCommand.Variations.LastOrDefault() is CommandVariation)) { Console.WriteLine("Cannot undo edit operation while a command variation is open (not yet completed or discarded) and no previous nested command is found."); return; } CanRedo = false; // Must be forced in order to avoid incoherence. this.CurrentExecutingCommand = (CommandVariation)this.CurrentVariatingCommand.Variations.Last(); this.CurrentVariatingCommand.Variations.RemoveAt(this.CurrentVariatingCommand.Variations.Count - 1); } else { // Takes the last operation this.CurrentExecutingCommand = this.UndoStack.Pop(); } if (this.CurrentExecutingCommand != null) { this.IsUndoing = true; if (Echo) { Console.WriteLine(this.CurrentExecutingCommand.CommandName); } // If redoable, initiates a command variation to capture the changes to be later redone. if (CanRedo) { this.StartCommandVariation(this.CurrentExecutingCommand.CommandName); } else { this.Pause(); // Prevents the Cancelled variations to be stored for Redo } // Executes the undo this.CurrentExecutingCommand.Execute(this); // Saves the captured variation into the redo stack. if (CanRedo) { var InverseVariation = this.CompleteCommandVariation(); if (InverseVariation != null) { this.RedoStack.Push(InverseVariation); } } else { this.Resume(); } // Maybe this undo was made inside a performing command, so point to it this.CurrentExecutingCommand = null; this.IsUndoing = false; } }
/// <summary> /// Generates inverse assignment or invocation for the supplied source variation and sense. /// </summary> public TVariation GenerateInverseVariation <TVariation>(TVariation SourceVariation, EEditOperationAction RequiredActionSense) where TVariation : Variation { TVariation GeneratedVariation = null; // If revert is required, then the call was made for the new undo registered in a currently executing redo. // This is the primary and original registration order (ready to be undone). // Else, if apply is required, then the call was made for the new redo registered in a currently executing undo. // This is the secondary registration order (ready to be redone). // In both cases the logic is the same. if (SourceVariation is AssignmentVariation) { var OriginalVariation = SourceVariation as AssignmentVariation; GeneratedVariation = (new AssignmentVariation(OriginalVariation.VariatingProperty, OriginalVariation.VariatingInstance, OriginalVariation.VariatingValue)) as TVariation; } else if (SourceVariation is CollectionVariation) { // Notice that the inversion only will take place for "Apply" (intended for Redo), because collection variations are stored ready for Undo. /* if (RequiredActionSense == EEditOperationAction.Apply) * { */ CollectionVariation OriginalVariation = SourceVariation as CollectionVariation; if (OriginalVariation.VariatingCollection.GetType().Name == typeof(EditableList <>).Name) { GeneratedVariation = GenerateInverseListVariation(OriginalVariation.VariatingCollection, OriginalVariation.VariatingAlterCode, OriginalVariation.PassedParameters) as TVariation; } else { GeneratedVariation = GenerateInverseDictionaryVariation(OriginalVariation.VariatingCollection, OriginalVariation.VariatingAlterCode, OriginalVariation.PassedParameters) as TVariation; } /* } * else * GeneratedVariation = SourceVariation; */ } else { var OriginalVariation = SourceVariation as CommandVariation; var NewGroupVariation = new CommandVariation(OriginalVariation.CommandName, OriginalVariation.AlterExistenceStatusWhileVariating); foreach (Variation RegVariation in OriginalVariation.Variations) { var InverseVariation = GenerateInverseVariation(RegVariation, RequiredActionSense); if (InverseVariation != null) { NewGroupVariation.AddVariation(InverseVariation); } } NewGroupVariation.Variations.Reverse(); GeneratedVariation = NewGroupVariation as TVariation; } return(GeneratedVariation); }