Пример #1
0
        // The InsertText worker.  Adds text to the tree at a specified position. 
        // text is either a string or char[] to insert. 
        internal void InsertTextInternal(TextPointer position, object text)
        { 
            TextTreeTextNode textNode;
            SplayTreeNode containingNode;
            TextPointer originalPosition;
            int symbolOffset; 
            int textLength;
            LogicalDirection direction; 
 
            Invariant.Assert(text is string || text is char[], "Unexpected type for 'text' parameter!");
 
            textLength = GetTextLength(text);

            if (textLength == 0)
                return; 

            DemandCreateText(); 
 
            position.SyncToTreeGeneration();
 
            if (Invariant.Strict)
            {
                if (position.Node.SymbolCount == 0)
                { 
                    // We expect only TextTreeTextNodes ever have zero symbol counts.
                    // This can happen in two cases: 
                    // 
                    // <TextNode referencedEdge=BeforeStart symbolCount=1+/> <TextNode referencedEdge=AfterEnd symbolCount=0/>
                    // or 
                    // <TextNode referencedEdge=BeforeStart symbolCount=0/> <TextNode referencedEdge=AfterEnd symbolCount=1+/>
                    //
                    Invariant.Assert(position.Node is TextTreeTextNode);
                    Invariant.Assert((position.Edge == ElementEdge.AfterEnd && position.Node.GetPreviousNode() is TextTreeTextNode && position.Node.GetPreviousNode().SymbolCount > 0) || 
                                 (position.Edge == ElementEdge.BeforeStart && position.Node.GetNextNode() is TextTreeTextNode && position.Node.GetNextNode().SymbolCount > 0));
                } 
            } 

            BeforeAddChange(); 

            // During document load we won't have listeners and we can save
            // an allocation on every insert.  This can easily save 1000's of allocations during boot.
            originalPosition = this.HasListeners ? new TextPointer(position, LogicalDirection.Backward) : null; 

            // Find a bordering TextTreeTextNode, if any. 
 
            // We know position already points to the current TextNode, if there is one, so
            // we can't append text to that node (it would disrespect position's gravity to do so). 
            // So we either have to find a neighboring text node with no position references, or
            // create a new node.

            // Look for a bordering text node. 
            if (position.Edge == ElementEdge.BeforeStart || position.Edge == ElementEdge.BeforeEnd)
            { 
                direction = LogicalDirection.Backward; 
            }
            else 
            {
                direction = LogicalDirection.Forward;
            }
            textNode = position.GetAdjacentTextNodeSibling(direction); 

            if (textNode != null) 
            { 
                // We can't use a text node that is already referred to by text positions.
                // Doing so could displace the positions, since they expect to remain at 
                // the node edge no matter what happens.
                if ((direction == LogicalDirection.Backward && textNode.AfterEndReferenceCount) ||
                    (direction == LogicalDirection.Forward && textNode.BeforeStartReferenceCount))
                { 
                    textNode = null;
                } 
            } 

            if (textNode == null) 
            {
                // No text node available.  Create and insert one.
                textNode = new TextTreeTextNode();
                textNode.InsertAtPosition(position); 
                containingNode = textNode.GetContainingNode();
            } 
            else 
            {
                // We didn't insert a new node, so splay textNode to the root so 
                // we don't invalidate any LeftSymbolCounts of ancestor nodes.
                textNode.Splay();
                containingNode = textNode.ParentNode;
            } 

            // Update the symbol counts. 
            textNode.SymbolCount += textLength; // This simultaneously updates textNode.IMECharCount. 
            UpdateContainerSymbolCount(containingNode, /* symbolCount */ textLength, /* charCount */ textLength);
 
            // Insert the raw text.
            symbolOffset = textNode.GetSymbolOffset(this.Generation);
            TextTreeText.InsertText(_rootNode.RootTextBlock, symbolOffset, text);
 
            // Handle undo.
            TextTreeUndo.CreateInsertUndoUnit(this, symbolOffset, textLength); 
 
            // Announce the change.
            NextGeneration(false /* deletedContent */); 

            AddChange(originalPosition, /* symbolCount */ textLength, /* charCount */ textLength, PrecursorTextChangeType.ContentAdded);

            // Notify the TextElement of a content change. 
            TextElement textElement = position.Parent as TextElement;
            if (textElement != null) 
            { 
                textElement.OnTextUpdated();
            } 
        }