Files
DynamicDataDisplay/Common/UndoSystem/UndoProvider.cs
2024-02-23 00:46:06 -05:00

155 lines
3.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.Common.UndoSystem
{
public class UndoProvider : INotifyPropertyChanged
{
private readonly ActionStack undoStack = new ActionStack();
private readonly ActionStack redoStack = new ActionStack();
public UndoProvider()
{
undoStack.IsEmptyChanged += OnUndoStackIsEmptyChanged;
redoStack.IsEmptyChanged += OnRedoStackIsEmptyChanged;
}
private bool isEnabled = true;
public bool IsEnabled
{
get { return isEnabled; }
set { isEnabled = value; }
}
private void OnUndoStackIsEmptyChanged(object sender, EventArgs e)
{
PropertyChanged.Raise(this, "CanUndo");
}
private void OnRedoStackIsEmptyChanged(object sender, EventArgs e)
{
PropertyChanged.Raise(this, "CanRedo");
}
public void AddAction(UndoAction action)
{
if (!isEnabled)
return;
if (state != UndoState.None)
return;
undoStack.Push(action);
redoStack.Clear();
}
public void Undo()
{
var action = undoStack.Pop();
redoStack.Push(action);
state = UndoState.Undoing;
try
{
action.Undo();
}
finally
{
state = UndoState.None;
}
}
public void Redo()
{
var action = redoStack.Pop();
undoStack.Push(action);
state = UndoState.Redoing;
try
{
action.Do();
}
finally
{
state = UndoState.None;
}
}
public bool CanUndo
{
get { return !undoStack.IsEmpty; }
}
public bool CanRedo
{
get { return !redoStack.IsEmpty; }
}
private UndoState state = UndoState.None;
public UndoState State
{
get { return state; }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private readonly Dictionary<CaptureKeyHolder, object> captureHolders = new Dictionary<CaptureKeyHolder, object>();
public void CaptureOldValue(DependencyObject target, DependencyProperty property, object oldValue)
{
captureHolders[new CaptureKeyHolder { Target = target, Property = property }] = oldValue;
}
public void CaptureNewValue(DependencyObject target, DependencyProperty property, object newValue)
{
var holder = new CaptureKeyHolder { Target = target, Property = property };
if (captureHolders.ContainsKey(holder))
{
object oldValue = captureHolders[holder];
captureHolders.Remove(holder);
if (!Object.Equals(oldValue, newValue))
{
var action = new DependencyPropertyChangedUndoAction(target, property, oldValue, newValue);
AddAction(action);
}
}
}
private sealed class CaptureKeyHolder
{
public DependencyObject Target { get; set; }
public DependencyProperty Property { get; set; }
public override int GetHashCode()
{
return Target.GetHashCode() ^ Property.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj == null) return false;
CaptureKeyHolder other = obj as CaptureKeyHolder;
if (other == null) return false;
return Target == other.Target && Property == other.Property;
}
}
}
public enum UndoState
{
None,
Undoing,
Redoing
}
}