using System;
using System.Collections.Generic;
/// Undo-Redo code is written using the article:
/// http://www.codeproject.com/cs/design/commandpatterndemo.asp
// The Command Pattern and MVC Architecture
// By David Veeneman.
namespace CraftSynth.ImageEditor
{
///
/// Class is responsible for executing Undo - Redo operations
///
internal class UndoManager:IDisposable
{
#region Class Members
private Layers layers;
private List historyList;
private int nextUndo;
#endregion Class Members
#region Constructor
public UndoManager(Layers layerList)
{
layers = layerList;
ClearHistory();
}
#endregion Constructor
#region Destruction
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private bool _disposed = false;
protected void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
// Free any managed objects here.
if (this.historyList != null)
{
foreach (Command command in this.historyList)
{
if (command != null)
{
command.Dispose();
}
}
}
if (this.layers != null)
{
for (int i = 0; i < this.layers.Count; i++)
{
if (this.layers[i] != null)
{
this.layers[i].Dispose();
}
}
}
}
// Free any unmanaged objects here.
this._disposed = true;
}
}
~UndoManager()
{
this.Dispose(false);
}
#endregion
#region Properties
///
/// Return true if Undo operation is available
///
public bool CanUndo
{
get
{
// If the NextUndo pointer is -1, no commands to undo
if (nextUndo < 0 ||
nextUndo > historyList.Count - 1) // precaution
{
return false;
}
return true;
}
}
///
/// Return true if Redo operation is available
///
public bool CanRedo
{
get
{
// If the NextUndo pointer points to the last item, no commands to redo
if (nextUndo == historyList.Count - 1)
{
return false;
}
return true;
}
}
#endregion Properties
#region Public Functions
///
/// Clear History
///
public void ClearHistory()
{
if (this.historyList != null)
{
foreach (Command command in historyList)
{
if (command != null)
{
command.Dispose();
}
}
}
historyList = new List();
nextUndo = -1;
}
///
/// Add new command to history.
/// Called by client after executing some action.
///
///
public void AddCommandToHistory(Command command)
{
// Purge history list
TrimHistoryList();
// Add command and increment undo counter
historyList.Add(command);
nextUndo++;
}
///
/// Undo
///
public void Undo()
{
if (!CanUndo)
{
return;
}
// Get the Command object to be undone
Command command = historyList[nextUndo];
// Execute the Command object's undo method
command.Undo(layers);
// Move the pointer up one item
nextUndo--;
}
///
/// Redo
///
public void Redo()
{
if (!CanRedo)
{
return;
}
// Get the Command object to redo
int itemToRedo = nextUndo + 1;
Command command = historyList[itemToRedo];
// Execute the Command object
command.Redo(layers);
// Move the undo pointer down one item
nextUndo++;
}
#endregion Public Functions
#region Private Functions
private void TrimHistoryList()
{
// We can redo any undone command until we execute a new
// command. The new command takes us off in a new direction,
// which means we can no longer redo previously undone actions.
// So, we purge all undone commands from the history list.*/
// Exit if no items in History list
if (historyList.Count == 0)
{
return;
}
// Exit if NextUndo points to last item on the list
if (nextUndo == historyList.Count - 1)
{
return;
}
// Purge all items below the NextUndo pointer
for (int i = historyList.Count - 1; i > nextUndo; i--)
{
historyList.RemoveAt(i);
}
}
#endregion
}
}