JD2022-TU1/main/extern/Soundwich/Solution/Studio/UndoRedo.cs

191 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
namespace Studio
{
public interface IMemento<T>
{
IMemento<T> Restore(T target);
}
public class CompoundMemento<T> : IMemento<T>
{
private readonly List<IMemento<T>> _mementos = new List<IMemento<T>>();
public void Add(IMemento<T> m)
{
_mementos.Add(m);
}
public int Size => _mementos.Count;
#region IMemento Members
public CompoundMemento<T> Restore(T target)
{
CompoundMemento<T> inverse = new CompoundMemento<T>();
//starts from the last action
for (int i = _mementos.Count - 1; i >= 0; i--)
{
inverse.Add(_mementos[i].Restore(target));
}
return inverse;
}
IMemento<T> IMemento<T>.Restore(T target)
{
return Restore(target);
}
#endregion
}
public class UndoRedo<T>
{
private const int DEFAULT_CAPACITY = 100;
private bool supportRedo = true;
private bool inUndoRedo = false;
private CompoundMemento<T> tempMemento = null;
protected T subject;
#if LIMITED_CAPACITY
protected RoundStack<IMemento<T>> undoStack;
protected RoundStack<IMemento<T>> redoStack;
public UndoRedoHistory(T subject)
: this(subject, DEFAULT_CAPACITY)
{
}
public UndoRedoHistory(T subject, int capacity)
{
this.subject = subject;
undoStack = new RoundStack<IMemento<T>>(capacity);
redoStack = new RoundStack<IMemento<T>>(capacity);
}
#else
protected Stack<IMemento<T>> undoStack = new Stack<IMemento<T>>(DEFAULT_CAPACITY);
protected Stack<IMemento<T>> redoStack = new Stack<IMemento<T>>(DEFAULT_CAPACITY);
public UndoRedo(T subject)
{
this.subject = subject;
}
#endif
public bool InUndoRedo => inUndoRedo;
public int UndoCount => undoStack.Count;
public int RedoCount => redoStack.Count;
public bool SupportRedo
{
get { return supportRedo; }
set { supportRedo = value; }
}
public void BeginCompoundDo()
{
if (tempMemento != null)
throw new InvalidOperationException("Previous complex memento wasn't commited.");
tempMemento = new CompoundMemento<T>();
}
public void EndCompoundDo()
{
if (tempMemento == null)
throw new InvalidOperationException("Ending a non-existing complex memento");
_Do(tempMemento);
tempMemento = null;
}
public void Do(IMemento<T> m)
{
if (inUndoRedo)
throw new InvalidOperationException("Involking do within an undo/redo action.");
if (tempMemento == null)
{
_Do(m);
}
else
{
tempMemento.Add(m);
}
}
private void _Do(IMemento<T> m)
{
Console.WriteLine(m.GetType().ToString());
redoStack.Clear();
undoStack.Push(m);
}
public void Undo()
{
if (tempMemento != null)
throw new InvalidOperationException("The complex memento wasn't commited.");
inUndoRedo = true;
if (CanUndo)
{
IMemento<T> top = undoStack.Pop();
if (top != null)
{
redoStack.Push(top.Restore(subject));
}
}
inUndoRedo = false;
}
public void Redo()
{
if (tempMemento != null)
throw new InvalidOperationException("The complex memento wasn't commited.");
inUndoRedo = true;
if (CanRedo)
{
IMemento<T> top = redoStack.Pop();
if (top != null)
{
undoStack.Push(top.Restore(subject));
}
}
inUndoRedo = false;
}
public bool CanUndo => (undoStack.Count != 0);
public bool CanRedo => (redoStack.Count != 0);
public void Clear()
{
undoStack.Clear();
redoStack.Clear();
}
public IMemento<T> PeekUndo()
{
return undoStack.Count > 0 ? undoStack.Peek() : null;
}
public IMemento<T> PeekRedo()
{
return redoStack.Count > 0 ? redoStack.Peek() : null;
}
}
}