UndoEngine.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / UndoEngine.cs / 1305376 / UndoEngine.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------

namespace System.Activities.Presentation 
{
    using System; 
    using System.Collections.Generic; 
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization; 
    using System.Linq;
    using System.Runtime;

    [Fx.Tag.XamlVisible(false)] 
    public class UndoEngine : IUndoEngineOperations
    { 
        const int capacity = 100; 
        List undoBuffer;
        List redoBuffer; 
        EditingContext context;
        Bookmark bookmark;
        //interface which contains actual implementation of AddUndoUnit, Undo and Redo operations
        IUndoEngineOperations undoEngineImpl = null; 

        public event EventHandler UndoUnitAdded; 
        public event EventHandler UndoUnitDiscarded; 
        internal event EventHandler ExecuteUndo;
        public event EventHandler UndoRedoBufferChanged; 

        public UndoEngine(EditingContext context)
        {
            this.context = context; 
            undoBuffer = new List(capacity);
            redoBuffer = new List(capacity); 
            this.undoEngineImpl = this; 
        }
 
        //CreateBookmark - creates a new UndoUnit which gatters all edits in its
        //undo unit list. all changes in bookmark appear as a one change and can be
        //undoned or redoned as a one set.
        internal Bookmark CreateBookmark(string bookmarkName) 
        {
            //only one bookmark is supported 
            if (null == this.bookmark) 
            {
                //create bookmark undo unit, and give it a description 
                BookmarkUndoUnit unit = new BookmarkUndoUnit(this.context)
                {
                    Description = bookmarkName ?? string.Format(CultureInfo.InvariantCulture, "Bookmark {0}", Guid.NewGuid()),
                }; 
                //create bookmark, and pass bookmark undo unit to it.
                this.bookmark = new Bookmark(this, unit); 
                //switch implementation of AddUndoUnit, Undo, Redo to be delegated through bookmark 
                this.undoEngineImpl = bookmark;
                return this.bookmark; 
            }
            throw FxTrace.Exception.AsError(new NotSupportedException(SR.UndoEngine_NestedBookmarksException));
        }
 
        public IEnumerable GetUndoActions()
        { 
            return this.undoBuffer.Select(p => p.Description); 
        }
 
        public IEnumerable GetRedoActions()
        {
            return this.redoBuffer.Select(p => p.Description);
        } 

        void NotifyChange() 
        { 
            if (null != this.UndoRedoBufferChanged)
            { 
                this.UndoRedoBufferChanged(this, EventArgs.Empty);
            }
        }
 

        public void AddUndoUnit(UndoUnit unit) 
        { 
            if (unit == null)
            { 
                throw FxTrace.Exception.ArgumentNull("unit");
            }
            this.undoEngineImpl.AddUndoUnitCore(unit);
            this.NotifyChange(); 
        }
 
        public bool Undo() 
        {
            this.IsUndoRedoInProgress = true; 
            bool succeeded = this.undoEngineImpl.UndoCore();
            this.IsUndoRedoInProgress = false;
            if (succeeded)
            { 
                this.NotifyChange();
            } 
            return succeeded; 
        }
 
        public bool Redo()
        {
            this.IsUndoRedoInProgress = true;
            bool succeeded = this.undoEngineImpl.RedoCore(); 
            this.IsUndoRedoInProgress = false;
            if (succeeded) 
            { 
                this.NotifyChange();
            } 
            return succeeded;
        }

        public bool IsUndoRedoInProgress 
        {
            get; 
            private set; 
        }
 
        void IUndoEngineOperations.AddUndoUnitCore(UndoUnit unit)
        {
            undoBuffer.Add(unit);
            RaiseUndoUnitAdded(unit); 

            if (undoBuffer.Count > capacity) 
            { 
                undoBuffer.RemoveAt(0);
                RaiseUndoUnitDiscarded(); 
            }

            redoBuffer.Clear();
        } 

 
        bool IUndoEngineOperations.UndoCore() 
        {
            bool succeeded = false; 
            if (undoBuffer.Count > 0)
            {
                UndoUnit unitToUndo = undoBuffer.Last();
                undoBuffer.RemoveAt(undoBuffer.Count - 1); 
                unitToUndo.Undo();
                redoBuffer.Add(unitToUndo); 
                RaiseExecuteUndo(unitToUndo); 
                succeeded = true;
            } 
            return succeeded;
        }

        bool IUndoEngineOperations.RedoCore() 
        {
            bool succeeded = false; 
            if (redoBuffer.Count > 0) 
            {
                UndoUnit unitToRedo = redoBuffer.Last(); 
                redoBuffer.RemoveAt(redoBuffer.Count - 1);
                unitToRedo.Redo();
                undoBuffer.Add(unitToRedo);
                succeeded = true; 
            }
            return succeeded; 
        } 

        void RaiseUndoUnitAdded(UndoUnit unit) 
        {
            if (this.UndoUnitAdded != null)
            {
                this.UndoUnitAdded(this, new UndoUnitEventArgs() { UndoUnit = unit }); 
            }
        } 
 
        void RaiseUndoUnitDiscarded()
        { 
            if (this.UndoUnitDiscarded != null)
            {
                this.UndoUnitDiscarded(this, null);
            } 
        }
 
        void RaiseExecuteUndo(UndoUnit unitToUndo) 
        {
            if (this.ExecuteUndo != null) 
            {
                this.ExecuteUndo(this, new UndoUnitEventArgs() { UndoUnit = unitToUndo });
            }
        } 

        //Bookmark implmeentation - implements core UndoEngine operations + IDisposable - 
        //default bookmark behaviour is to Rollback changes, unless commited explicitly. 
        //usage of IDisposable enables usage of pattern:
        // using (Bookmark b = new Bookmark()).... 
        internal sealed class Bookmark : IDisposable, IUndoEngineOperations
        {
            BookmarkUndoUnit containerUndoUnit;
            UndoEngine undoEngine; 
            bool isCommited = false;
            bool isRolledBack = false; 
            bool isDisposed = false; 

            internal Bookmark(UndoEngine undoEngine, BookmarkUndoUnit undoUnit) 
            {
                this.undoEngine = undoEngine;
                this.containerUndoUnit = undoUnit;
            } 

 
            public void CommitBookmark() 
            {
                //cannot commit more than once... 
                if (this.isDisposed)
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.UndoEngine_OperationNotAllowed, "CommitBookmark")));
                } 

                this.isCommited = true; 
                //restore original undo engine implementation 
                this.undoEngine.undoEngineImpl = this.undoEngine;
                //get rid of the bookmark 
                this.undoEngine.bookmark = null;
                //check if bookmark has any changes
                if (this.containerUndoUnit.DoList.Count != 0 || this.containerUndoUnit.RedoList.Count != 0)
                { 
                    //add all changes in bookmark into a undo list as a one element
                    this.undoEngine.AddUndoUnit(this.containerUndoUnit); 
                } 
                //dispose bookmark
                this.Dispose(); 
            }

            public void RollbackBookmark()
            { 
                //cannot rollback more than once
                if (this.isDisposed) 
                { 
                    throw FxTrace.Exception.AsError(new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.UndoEngine_OperationNotAllowed, "RollbackBookmark")));
                } 
                this.isRolledBack = true;
                //get through the list of all accumulated changes and reverse each of them
                foreach (UndoUnit unit in this.containerUndoUnit.DoList.Reverse())
                { 
                    unit.Undo();
                } 
                //clear the lists 
                this.containerUndoUnit.DoList.Clear();
                this.containerUndoUnit.RedoList.Clear(); 

                //restore original undo engine implementation
                this.undoEngine.undoEngineImpl = this.undoEngine;
                //get rid of the bookmark 
                this.undoEngine.bookmark = null;
                //dispose bookmark 
                this.Dispose(); 
            }
 
            public void Dispose()
            {
                if (!this.isDisposed)
                { 
                    GC.SuppressFinalize(this);
                    DisposeInternal(); 
                } 
            }
 
            void DisposeInternal()
            {
                if (!this.isDisposed)
                { 
                    //if not commited or rolled back - rollback by default
                    if (!this.isCommited && !this.isRolledBack) 
                    { 
                        this.RollbackBookmark();
                    } 
                    this.isDisposed = true;
                }
            }
 
            void IUndoEngineOperations.AddUndoUnitCore(UndoUnit unit)
            { 
                //add element to Undo list 
                this.containerUndoUnit.DoList.Add(unit);
                //clear redo list 
                this.containerUndoUnit.RedoList.Clear();
            }

            bool IUndoEngineOperations.UndoCore() 
            {
                //if there is anything to undo 
                bool succeeded = false; 
                if (this.containerUndoUnit.DoList.Count > 0)
                { 
                    //get the last element done
                    UndoUnit unitToUndo = this.containerUndoUnit.DoList.Last();
                    //remove it
                    this.containerUndoUnit.DoList.RemoveAt(this.containerUndoUnit.DoList.Count - 1); 
                    //undo it
                    unitToUndo.Undo(); 
                    //and insert to the head of redo list 
                    this.containerUndoUnit.RedoList.Insert(0, unitToUndo);
                    succeeded = true; 
                }
                return succeeded;
            }
 
            bool IUndoEngineOperations.RedoCore()
            { 
                //if there is anything to redo 
                bool succeeded = false;
                if (this.containerUndoUnit.RedoList.Count > 0) 
                {
                    //get first element to redo
                    UndoUnit unitToRedo = this.containerUndoUnit.RedoList.First();
                    //remove it 
                    this.containerUndoUnit.RedoList.RemoveAt(0);
                    //redo it 
                    unitToRedo.Redo(); 
                    //add it to the end of undo list
                    this.containerUndoUnit.DoList.Add(unitToRedo); 
                    succeeded = true;
                }
                return succeeded;
            } 
        }
 
 

    } 


}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK