#region File Description //----------------------------------------------------------------------------- // CommandHistory.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion //----------------------------------------------------------------------------- // CommandHistory.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #region Using Statements using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Diagnostics; using System.Text; #endregion namespace Xna.Tools { /// /// This class provides Undo/Redo feature. /// public class CommandHistory { #region Properties /// /// Changed event that fired when command history changed. /// public event EventHandler Changed; /// /// It returns true if it can process undo; otherwise it returns false. /// public bool CanUndo { get { return commands.CanUndo; } } /// /// It returns true if it can process redo; otherwise it returns false. /// public bool CanRedo { get { return commands.CanRedo; } } #endregion #region Public Methods /// /// Make sure CommandHistory added as a service to given site. /// /// /// You have to make sure added IServiceContainer to this /// serviceProvider. public static CommandHistory EnsureHasService(IServiceProvider serviceProvider) { CommandHistory result = null; IServiceProvider sp = serviceProvider; if (sp != null) { // Add this CommandHistory service if given service // doesn't contains it. result = sp.GetService(typeof(CommandHistory)) as CommandHistory; if (result == null) { // If there are no service, added new instance. IServiceContainer s = sp.GetService(typeof(IServiceContainer)) as IServiceContainer; if (s == null) { throw new InvalidOperationException( CurveControlResources.RequireServiceContainer); } result = new CommandHistory(); s.AddService(typeof(CommandHistory), result); } } else { // If they don't have ISite, returns static instance. if (staticCommandHistory == null) staticCommandHistory = new CommandHistory(); result = staticCommandHistory; } return result; } /// /// Execute given command and added to history. /// /// public void Do(ICommand command) { if (command == null) throw new ArgumentNullException("command"); command.Execute(); Add(command); } /// /// Add command to history. /// /// public void Add(ICommand command) { DebugPrintCommand("Add", command); // Add given command to commands or recordingCommands. if (recordingCommands != null) { recordingCommands.Add(command); } else { commands.Add(command); if (Changed != null) Changed(this, EventArgs.Empty); } } /// /// Undo command. /// public void Undo() { if (recordingNestCount != 0) throw new InvalidOperationException(String.Format( CurveControlResources.CantExecuteCommandHistory, "Undo")); DebugPrintCommand("Undo", -1); commands.Undo(); if (Changed != null) Changed(this, EventArgs.Empty); } /// /// Redo command. /// public void Redo() { if (recordingNestCount != 0) throw new InvalidOperationException(String.Format( CurveControlResources.CantExecuteCommandHistory, "Redo")); DebugPrintCommand("Redo", 0); commands.Redo(); if (Changed != null) Changed(this, EventArgs.Empty); } /// /// Record multiple commands as one command. /// public void BeginRecordCommands() { if (recordingNestCount++ == 0) recordingCommands = new CommandCollection(); } /// /// Stop recording commands and added as a command. /// public void EndRecordCommands() { if (--recordingNestCount != 0) return; // Added recorded commands to commands. // If recording commands recored one command, we just add that command to // main commands. if (recordingCommands.Count != 0) { if (recordingCommands.Count == 1) commands.Add(recordingCommands[0]); else commands.Add(recordingCommands); if (Changed != null) Changed(this, EventArgs.Empty); } recordingCommands = null; } #endregion #region Private Members /// /// Main CommandQueue. /// CommandCollection commands = new CommandCollection(); /// /// Sub CommandQueue that uses for command recoording. /// CommandCollection recordingCommands = null; /// /// For keep tracking nested call of Begin/EndRecoord method. /// int recordingNestCount = 0; /// /// Static command history that only avilable when user doesn't provide /// ISite object. /// static CommandHistory staticCommandHistory = null; #endregion #region Debug Code [Conditional("DEBUG")] static void DebugPrintCommand(string prefix, ICommand command) { System.Diagnostics.Debugger.Log(0, "CmdHistory", String.Format("{0}:{1}\n", prefix, command.ToString())); CommandCollection cq = command as CommandCollection; if (cq != null) { for (int i = 0; i < cq.Count; ++i) { System.Diagnostics.Debugger.Log(0, "CmdHistory", String.Format(" [{0}]:{1}\n", i, cq[i].ToString())); } } } [Conditional("DEBUG")] private void DebugPrintCommand(string prefix, int offset) { DebugPrintCommand(prefix, commands[commands.Index + offset]); } #endregion } }