Initial Commit
This commit is contained in:
51
Common/UndoSystem/ActionStack.cs
Normal file
51
Common/UndoSystem/ActionStack.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.UndoSystem
|
||||
{
|
||||
[DebuggerDisplay("Count = {Count}")]
|
||||
public sealed class ActionStack
|
||||
{
|
||||
private readonly Stack<UndoAction> stack = new Stack<UndoAction>();
|
||||
|
||||
public void Push(UndoAction action)
|
||||
{
|
||||
stack.Push(action);
|
||||
|
||||
if (stack.Count == 1)
|
||||
RaiseIsEmptyChanged();
|
||||
}
|
||||
|
||||
public UndoAction Pop()
|
||||
{
|
||||
var action = stack.Pop();
|
||||
|
||||
if (stack.Count == 0)
|
||||
RaiseIsEmptyChanged();
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
public int Count { get { return stack.Count; } }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
stack.Clear();
|
||||
RaiseIsEmptyChanged();
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return stack.Count == 0; }
|
||||
}
|
||||
|
||||
private void RaiseIsEmptyChanged()
|
||||
{
|
||||
IsEmptyChanged.Raise(this);
|
||||
}
|
||||
public event EventHandler IsEmptyChanged;
|
||||
}
|
||||
}
|
||||
34
Common/UndoSystem/CollectionAddAction.cs
Normal file
34
Common/UndoSystem/CollectionAddAction.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.UndoSystem
|
||||
{
|
||||
public sealed class CollectionAddAction<T> : UndoAction
|
||||
{
|
||||
private readonly ICollection<T> collection;
|
||||
private readonly T item;
|
||||
|
||||
public CollectionAddAction(ICollection<T> collection, T item)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException("collection");
|
||||
if (item == null)
|
||||
throw new ArgumentNullException("addedItem");
|
||||
|
||||
this.collection = collection;
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
public override void Do()
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
collection.Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Common/UndoSystem/CollectionRemoveAction.cs
Normal file
36
Common/UndoSystem/CollectionRemoveAction.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.UndoSystem
|
||||
{
|
||||
public sealed class CollectionRemoveAction<T> : UndoAction
|
||||
{
|
||||
private readonly IList<T> collection;
|
||||
private readonly T item;
|
||||
private readonly int index;
|
||||
|
||||
public CollectionRemoveAction(IList<T> collection, T item, int index)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException("collection");
|
||||
if (item == null)
|
||||
throw new ArgumentNullException("addedItem");
|
||||
|
||||
this.collection = collection;
|
||||
this.item = item;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public override void Do()
|
||||
{
|
||||
collection.Remove(item);
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
collection.Insert(index, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Common/UndoSystem/DependencyPropertyChangedUndoAction.cs
Normal file
42
Common/UndoSystem/DependencyPropertyChangedUndoAction.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.UndoSystem
|
||||
{
|
||||
public class DependencyPropertyChangedUndoAction : UndoAction
|
||||
{
|
||||
private readonly DependencyProperty property;
|
||||
private readonly DependencyObject target;
|
||||
private readonly object oldValue;
|
||||
private readonly object newValue;
|
||||
|
||||
public DependencyPropertyChangedUndoAction(DependencyObject target, DependencyProperty property, object oldValue, object newValue)
|
||||
{
|
||||
this.target = target;
|
||||
this.property = property;
|
||||
this.oldValue = oldValue;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
public DependencyPropertyChangedUndoAction(DependencyObject target, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
this.target = target;
|
||||
this.property = e.Property;
|
||||
this.oldValue = e.OldValue;
|
||||
this.newValue = e.NewValue;
|
||||
}
|
||||
|
||||
public override void Do()
|
||||
{
|
||||
target.SetValue(property, newValue);
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
target.SetValue(property, oldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Common/UndoSystem/LambdaUndoAction.cs
Normal file
34
Common/UndoSystem/LambdaUndoAction.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.UndoSystem
|
||||
{
|
||||
public sealed class LambdaUndoAction : UndoAction
|
||||
{
|
||||
private readonly Action doAction;
|
||||
private readonly Action undoAction;
|
||||
|
||||
public LambdaUndoAction(Action doAction, Action undoAction)
|
||||
{
|
||||
if (doAction == null)
|
||||
throw new ArgumentNullException("doHander");
|
||||
if (undoAction == null)
|
||||
throw new ArgumentNullException("undoAction");
|
||||
|
||||
this.doAction = doAction;
|
||||
this.undoAction = undoAction;
|
||||
}
|
||||
|
||||
public override void Do()
|
||||
{
|
||||
doAction();
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
undoAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Common/UndoSystem/UndoAction.cs
Normal file
13
Common/UndoSystem/UndoAction.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.UndoSystem
|
||||
{
|
||||
public abstract class UndoAction
|
||||
{
|
||||
public abstract void Do();
|
||||
public abstract void Undo();
|
||||
}
|
||||
}
|
||||
154
Common/UndoSystem/UndoProvider.cs
Normal file
154
Common/UndoSystem/UndoProvider.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user