view Commands/CommandStack.cs @ 13:6b762694f051

Check size of dictionary so that we don't have to get the values when we've got an empty dictionary no-open-ticket
author IBBoard <dev@ibboard.co.uk>
date Tue, 06 Jan 2009 19:27:47 +0000
parents 961030992bd2
children 0352fa33ee8f
line wrap: on
line source

using System;
using System.Collections;

namespace IBBoard.Commands
{
	/// <summary>
	/// Summary description for CommandStack.
	/// </summary>
	public class CommandStack
	{
		private ArrayList commandStack;
		private int listPos = -1;
		private int listMax = -1;
		private int cleanPos;

		public event MethodInvoker CommandStackUpdated;

		public CommandStack()
		{
			commandStack = new ArrayList(10);
			cleanPos = -1;
		}

		public bool IsDirty()
		{
			return listPos!=cleanPos;
		}

		public void setCleanMark()
		{
			cleanPos = listPos;
		}

		public bool IsEmpty()
		{
			return listMax == -1;
		}

		public bool CanUndo()
		{
			return listPos > -1;
		}

		public int UndoLength
		{
			get { return listPos + 1; }
		}

		public int RedoLength
		{
			get { return listMax - listPos; }
		}

		public bool CanRedo()
		{
			return listPos < listMax;
		}

		public void Reset()
		{
			commandStack.Clear();
			listMax = -1;
			listPos = -1;
			DoCommandStackUpdated();
		}

		public void Undo()
		{
			if (CanUndo())
			{
				((Command)commandStack[listPos]).Undo();
				listPos--;
				DoCommandStackUpdated();
			}
			else
			{
				throw new InvalidOperationException("Cannot undo action on empty command stack");
			}
		}

		public void Redo()
		{
			if (CanRedo())
			{
				((Command)commandStack[listPos+1]).Redo();
				listPos++;
				DoCommandStackUpdated();
			}
			else
			{
				throw new InvalidOperationException("No actions to redo");
			}
		}

		public bool Execute(Command cmd)
		{
			if (cmd.CanExecute())
			{
				if (cmd.Execute())
				{
					//if we can't redo, i.e. there's no commands beyond our current point, add to the end else insert
					if (!CanRedo())
					{
						commandStack.Add(cmd);
						listPos++;
					}
					else
					{
						if (cleanPos>listPos)
						{
							cleanPos = -2;
						}

						//else overwrite at our current position, setting the listMax value will ignore any commands we could have redone beyond here
						commandStack[++listPos] = cmd;
					}

					listMax = listPos;
					DoCommandStackUpdated();
					return true;
				}
				else
				{
					throw new InvalidOperationException("Executable command failed to execute");
				}
			}
			else
			{
				return false;
			}
		}

		protected void DoCommandStackUpdated()
		{
			if (CommandStackUpdated!=null)
			{
				CommandStackUpdated();
			}
		}

		public Command PeekUndoCommand()
		{
			return PeekUndoCommand(1);
		}

		public Command PeekUndoCommand(int backCount)
		{
			backCount = backCount - 1;
			if (backCount > -1 && backCount <= listPos)
			{
				return (Command)commandStack[listPos-backCount];
			}
			else
			{
				return null;
			}
		}

		public Command PeekRedoCommand()
		{
			return PeekRedoCommand(1);
		}

		public Command PeekRedoCommand(int forwardCount)
		{
			if (forwardCount > 0 && listPos+forwardCount <= listMax)
			{
				return (Command)commandStack[listPos+forwardCount];
			}
			else
			{
				return null;
			}
		}
	}
}