TextTreeDeleteContentUndoUnit.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 / wpf / src / Framework / System / Windows / Documents / TextTreeDeleteContentUndoUnit.cs / 1407647 / TextTreeDeleteContentUndoUnit.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Undo unit for TextContainer.DeleteContent calls. 
//
// History: 
//  03/03/2004 : [....] - Created
//
//---------------------------------------------------------------------------
 
using MS.Internal;
using System; 
using System.IO; 
using System.Windows.Controls;
using System.Windows.Markup; 
using System.Xml;
using System.Security;

namespace System.Windows.Documents 
{
    // Undo unit for TextContainer.DeleteContent calls. 
    internal class TextTreeDeleteContentUndoUnit : TextTreeUndoUnit 
    {
        //----------------------------------------------------- 
        //
        //  Constructors
        //
        //----------------------------------------------------- 

        #region Constructors 
 
        // Creates a new instance.
        // start/end span the content to copy into the new undo unit -- they 
        // should always share the same scoping TextElement.
        internal TextTreeDeleteContentUndoUnit(TextContainer tree, TextPointer start, TextPointer end) : base(tree, start.GetSymbolOffset())
        {
            TextTreeNode node; 
            TextTreeNode haltNode;
 
            start.DebugAssertGeneration(); 
            end.DebugAssertGeneration();
            Invariant.Assert(start.GetScopingNode() == end.GetScopingNode(), "start/end have different scope!"); 

            node = start.GetAdjacentNode(LogicalDirection.Forward);
            haltNode = end.GetAdjacentNode(LogicalDirection.Forward);
 
            // Walk the content, copying runs as we go.
            _content = CopyContent(node, haltNode); 
        } 

        #endregion Constructors 

        //------------------------------------------------------
        //
        //  Public Methods 
        //
        //----------------------------------------------------- 
 
        #region Public Methods
 
        // Called by the undo manager.  Restores tree state to its condition
        // when the unit was created.  Assumes the tree state matches conditions
        // just after the unit was created.
        // 
        // Note that inside the scope of this call we'll also create redo records,
        // which are very fragmented -- one for each TextPointerContext run. 
        // In the future, if we have perf issues, we could consider disabling 
        // reentrant calls to the UndoManager and instead manually adding a single
        // undo unit here to prevent the fragmentation. 
        public override void DoCore()
        {
            TextPointer navigator;
            ContentContainer container; 

            VerifyTreeContentHashCode(); 
 
            // We need forward gravity to make following inserts work.
            navigator = new TextPointer(this.TextContainer, this.SymbolOffset, LogicalDirection.Forward); 

            for (container = _content; container != null; container = container.NextContainer)
            {
                container.Do(navigator); 
            }
        } 
 
        #endregion Public Methods
 
        //------------------------------------------------------
        //
        //  Internal Methods
        // 
        //------------------------------------------------------
 
        #region Internal Methods 

        // Used also in TextTreeExtractElementUndoUnit 
        internal static TableColumn[] SaveColumns(Table table)
        {
            TableColumn[] savedColumns;
            if (table.Columns.Count > 0) 
            {
                savedColumns = new TableColumn[table.Columns.Count]; 
                for (int columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++) 
                {
                    savedColumns[columnIndex] = CopyColumn(table.Columns[columnIndex]); 
                }
            }
            else
            { 
                savedColumns = null;
            } 
 
            return savedColumns;
        } 

        // Used also in TextTreeExtractElementUndoUnit
        internal static void RestoreColumns(Table table, TableColumn[] savedColumns)
        { 
            if (savedColumns != null)
            { 
                for (int columnIndex = 0; columnIndex < savedColumns.Length; columnIndex++) 
                {
                    if (table.Columns.Count <= columnIndex) 
                    {
                        table.Columns.Add(CopyColumn(savedColumns[columnIndex]));
                    }
                } 
            }
        } 
 
        private static TableColumn CopyColumn(TableColumn sourceTableColumn)
        { 
            TableColumn newTableColumn = new TableColumn();
            LocalValueEnumerator properties = sourceTableColumn.GetLocalValueEnumerator();
            while (properties.MoveNext())
            { 
                LocalValueEntry propertyEntry = properties.Current;
                if (!propertyEntry.Property.ReadOnly) 
                { 
                    newTableColumn.SetValue(propertyEntry.Property, propertyEntry.Value);
                } 
            }

            return newTableColumn;
        } 

        #endregion Internal Methods 
 
        //-----------------------------------------------------
        // 
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        // Walks the tree from node to the end of its sibling list, 
        // copying content along the way,
        // halting when/if haltNode is encountered. haltNode may be 
        // null, in which case we walk to the end of the sibling list.
        //
        // Returns a ContentContainer holding a deep copy of all content
        // walked. 
        //
        // This method is called recursively when TextElement nodes 
        // are encountered. 
        private ContentContainer CopyContent(TextTreeNode node, TextTreeNode haltNode)
        { 
            ContentContainer firstContainer;
            ContentContainer container;
            ContentContainer nextContainer;
            TextTreeTextNode textNode; 
            TextTreeObjectNode objectNode;
            TextTreeTextElementNode elementNode; 
 
            firstContainer = null;
            container = null; 

            while (node != haltNode && node != null)
            {
                textNode = node as TextTreeTextNode; 
                if (textNode != null)
                { 
                    node = CopyTextNode(textNode, haltNode, out nextContainer); 
                }
                else 
                {
                    objectNode = node as TextTreeObjectNode;
                    if (objectNode != null)
                    { 
                        node = CopyObjectNode(objectNode, out nextContainer);
                    } 
                    else 
                    {
                        Invariant.Assert(node is TextTreeTextElementNode, "Unexpected TextTreeNode type!"); 
                        elementNode = (TextTreeTextElementNode)node;

                        node = CopyElementNode(elementNode, out nextContainer);
                    } 
                }
 
                if (container == null) 
                {
                    firstContainer = nextContainer; 
                }
                else
                {
                    container.NextContainer = nextContainer; 
                }
                container = nextContainer; 
            } 

            return firstContainer; 
        }

        // Copies a run of text into a ContentContainer.
        // Returns the next node to examine. 
        private TextTreeNode CopyTextNode(TextTreeTextNode textNode, TextTreeNode haltNode, out ContentContainer container)
        { 
            SplayTreeNode node; 
            char[] text;
            int count; 
            int symbolOffset;

            Invariant.Assert(textNode != haltNode, "Expect at least one node to copy!");
 
            symbolOffset = textNode.GetSymbolOffset(this.TextContainer.Generation);
 
            // Get a count of all the characters we're about to copy. 
            count = 0;
            node = textNode; 

            do
            {
                count += textNode.SymbolCount; 

                node = textNode.GetNextNode(); 
                textNode = node as TextTreeTextNode; 
            }
            while (textNode != null && textNode != haltNode); 

            // Allocate storage.
            text = new char[count];
 
            // Copy the text.
            TextTreeText.ReadText(this.TextContainer.RootTextBlock, symbolOffset, count, text, 0 /*startIndex*/); 
 
            container = new TextContentContainer(text);
 
            return (TextTreeNode)node;
        }

 
        /// 
        /// Copies an embedded UIElement into a ContentContainer. 
        /// Returns the next node to examine. 
        /// 
        ///  
        /// Critical: This function makes a security decision (checks for unmanaged code permission).
        /// TreatAsSafe: Doesn't call critical code and doesn't expose critical data.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private TextTreeNode CopyObjectNode(TextTreeObjectNode objectNode, out ContentContainer container)
        { 
            // XamlWriter.Save demands unmanaged code permission. Since it's not safe to assert 
            // here as custom type converters and value serializers can potentially execute
            // arbitrary code, we block the call to XamlWriter.Save in partial trust. 
            if (SecurityHelper.CheckUnmanagedCodePermission())
            {
                string xml;
 
                xml = XamlWriter.Save(objectNode.EmbeddedElement);
 
                container = new ObjectContentContainer(xml, objectNode.EmbeddedElement); 
            }
            else 
            {
                container = new ObjectContentContainer(null, null);
            }
 
            return (TextTreeNode)objectNode.GetNextNode();
        } 
 
        // Copies a TextElement and all its contained content into a ContentContainer.
        // Returns the next node to examine. 
        private TextTreeNode CopyElementNode(TextTreeTextElementNode elementNode, out ContentContainer container)
        {
            if(elementNode.TextElement is Table)
            { 
                container = new TableElementContentContainer(elementNode.TextElement as Table,
                                                        GetPropertyRecordArray(elementNode.TextElement), 
                                                        CopyContent((TextTreeNode)elementNode.GetFirstContainedNode(), null)); 

            } 
            else
            {
                container = new ElementContentContainer(elementNode.TextElement.GetType(),
                                                        GetPropertyRecordArray(elementNode.TextElement), 
                                                        elementNode.TextElement.Resources,
                                                        CopyContent((TextTreeNode)elementNode.GetFirstContainedNode(), null)); 
            } 

            return (TextTreeNode)elementNode.GetNextNode(); 
        }

        #endregion Private methods
 
        //-----------------------------------------------------
        // 
        //  Private Types 
        //
        //----------------------------------------------------- 

        #region Private Types

        // ContentContainer encapsulates a serialized copy of one of 
        //  - Text run.
        //  - UIElement. 
        //  - TextElement. 
        private abstract class ContentContainer
        { 
            // Inserts the content held by this container at a specified position.
            // Navigator is positioned just past the new content on return.
            // Navigator is expected to have forward gravity.
            internal abstract void Do(TextPointer navigator); 

            // The content following this container.  Always a different 
            // container type. 
            internal ContentContainer NextContainer
            { 
                get { return _nextContainer; }
                set { _nextContainer = value; }
            }
 
            private ContentContainer _nextContainer;
        } 
 
        // A serialized text run.
        private class TextContentContainer : ContentContainer 
        {
            internal TextContentContainer(char[] text)
            {
                _text = text; 
            }
 
            // Inserts the content held by this container at a specified position. 
            // Navigator is positioned just past the new content on return.
            // Navigator is expected to have forward gravity. 
            internal override void Do(TextPointer navigator)
            {
                navigator.TextContainer.InsertTextInternal(navigator, _text);
            } 

            // The text covered by this run. 
            private readonly char[] _text; 
        }
 
        // A serialized UIElement.
        private class ObjectContentContainer : ContentContainer
        {
            internal ObjectContentContainer(string xml, object element) 
            {
                _xml = xml; 
 
                // Store a strong reference to the deleted element.
                // Note that we are not supposed to use this reference in any other way 
                // as just to prevent garbage collector to delete object.
                // We need to keep it in memory for ensuring that image cache
                // keeps the same uri references to image bitmaps.
                // Otherwise uri-s of packaged (pasted) images will be broken 
                // on undo.
                _element = element; 
            } 

            // Inserts the content held by this container at a specified position. 
            // Navigator is positioned just past the new content on return.
            // Navigator is expected to have forward gravity.
            internal override void Do(TextPointer navigator)
            { 
                DependencyObject embeddedObject = null;
 
                // Get the object to be inserted. 
                // If xml is null which we set it not to call SaveAsXml in the partial trust envirnment,
                // create the dummy Grid object to be inserted so that we can [....] TextContainer 
                // count with the undo unit.
                if (_xml != null)
                {
                    try 
                    {
                        embeddedObject = (DependencyObject)XamlReader.Load(new XmlTextReader(new StringReader(_xml))); 
                    } 
                    catch (XamlParseException e)
                    { 
                        Invariant.Assert(e != null); // Placed here for debugging convenience - to be able to see the exception.
                    }
                }
 
                // When we cannot parse the object back, we loose it and substitute by an empty Grid
                // as an embeddedElement placeholder. 
                if (embeddedObject == null) 
                {
                    embeddedObject = new Grid(); 
                }

                navigator.TextContainer.InsertEmbeddedObjectInternal(navigator, embeddedObject);
            } 

            // Serialized UIElement xml. 
            private readonly string _xml; 

            // Stores a strong reference to the deleted content to make sure 
            // that all image data remains in image cache.
            // The object is not supposed to be used in any other sense
            // in this undo unit - only as a strong reference.
            // Image cache keeps the association between an image bitmap data 
            // and its source url until the bitmapdata is referred to by a strong reference.
            // That's why we need this. 
            private readonly Object _element; 
        }
 
        // A serialized TextElement.
        private class ElementContentContainer : ContentContainer
        {
            // Creates a new instance. 
            // childContainer holds all content covered by this TextElement.
            internal ElementContentContainer(Type elementType, PropertyRecord[] localValues, ResourceDictionary resources, ContentContainer childContainer) 
            { 
                _elementType = elementType;
                _localValues = localValues; 
                _childContainer = childContainer;
                _resources = resources;
            }
 
            // Inserts the content held by this container at a specified position.
            // Navigator is positioned just past the new content on return. 
            // Navigator is expected to have forward gravity. 
            internal override void Do(TextPointer navigator)
            { 
                ContentContainer container;
                TextElement element;

                // Insert the element. 
                element = (TextElement)Activator.CreateInstance(_elementType);
                element.Reposition(navigator, navigator); 
 
                // Get inside its scope.
                navigator.MoveToNextContextPosition(LogicalDirection.Backward); 

                // Set local values.
                //
                navigator.TextContainer.SetValues(navigator, TextTreeUndoUnit.ArrayToLocalValueEnumerator(_localValues)); 

                // Restore resources 
                element.Resources = _resources; 

                // Insert contained content. 
                for (container = _childContainer; container != null; container = container.NextContainer)
                {
                    container.Do(navigator);
                } 

                // Move outside the element's scope again. 
                navigator.MoveToNextContextPosition(LogicalDirection.Forward); 
            }
 
            // TextElement type.
            private readonly Type _elementType;

            // Local property values set on the TextElement. 
            private readonly PropertyRecord []_localValues;
 
            // Resources defined locally on the TextElement 
            private readonly ResourceDictionary _resources;
 
            // Contained content.
            private readonly ContentContainer _childContainer;
        }
 
        // A serialized Table Element
        private class TableElementContentContainer : ElementContentContainer 
        { 
            internal TableElementContentContainer(Table table, PropertyRecord []localValues, ContentContainer childContainer) :
                base(table.GetType(), localValues, table.Resources, childContainer) 
            {
                _cpTable = table.TextContainer.Start.GetOffsetToPosition(table.ContentStart);
                _columns = SaveColumns(table);
            } 

            internal override void Do(TextPointer navigator) 
            { 
                base.Do(navigator);
 
                if(_columns != null)
                {
                    TextPointer textPointerTable = new TextPointer(navigator.TextContainer.Start, _cpTable, LogicalDirection.Forward);
                    Table table = (Table) textPointerTable.Parent; 
                    RestoreColumns(table, _columns);
                } 
            } 

            private TableColumn[] _columns; 
            private int _cpTable;
        }

        #endregion Private Types 

        //----------------------------------------------------- 
        // 
        //  Private Fields
        // 
        //------------------------------------------------------

        #region Private Fields
 
        // Serialized content.
        private readonly ContentContainer _content; 
 
        #endregion Private Fields
    } 
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

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