Example #1
0
        //-----------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        #region Constructors

        /// <summary> 
        /// Structural Cache contructor.
        /// </summary> 
        /// <param name="owner">Owner of the conent</param> 
        /// <param name="textContainer">TextContainer representing content</param>
        internal StructuralCache(FlowDocument owner, TextContainer textContainer) 
        {
            Invariant.Assert(owner != null);
            Invariant.Assert(textContainer != null);
            Invariant.Assert(textContainer.Parent != null); 

            _owner = owner; 
            _textContainer = textContainer; 
            _backgroundFormatInfo = new BackgroundFormatInfo(this);
        } 
        // Adds a TextTreeInsertElementUndoUnit to the open parent undo unit, if any.
        // Called from TextContainer.InsertElement.
        internal static void CreateInsertElementUndoUnit(TextContainer tree, int symbolOffset, bool deep)
        {
            UndoManager undoManager;

            undoManager = GetOrClearUndoManager(tree);
            if (undoManager == null)
                return;

            undoManager.Add(new TextTreeInsertElementUndoUnit(tree, symbolOffset, deep));
        }
Example #3
0
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        #region Internal Methods

        // Dumps a TextContainer.
        internal static void Dump(TextContainer tree)
        {
            if (tree.RootNode == null)
            {
                Debug.WriteLine("<" + tree + "/>");
            }
            else
            {
                DumpNodeRecursive(tree.RootNode, 0);
            }
        }
Example #4
0
 // Dumps a TextContainer, xaml style.
 internal static void DumpFlat(TextContainer tree)
 {
     if (tree.RootNode == null)
     {
         Debug.WriteLine("<" + tree + "/>");
     }
     else
     {
         DumpFlat(tree.RootNode);
     }
 }
Example #5
0
        //-----------------------------------------------------
        //
        //  Constructors
        // 
        //-----------------------------------------------------
 
        #region Constructors 

        // Creates a TextTreeRootNode instance. 
        internal TextTreeRootNode(TextContainer tree)
        {
            _tree = tree;
#if REFCOUNT_DEAD_TEXTPOINTERS 
            _deadPositionList = new ArrayList(0);
#endif // REFCOUNT_DEAD_TEXTPOINTERS 
 
            // Root node has two imaginary element edges to match TextElementNode semantics.
            _symbolCount = 2; 

            // CaretUnitBoundaryCache always starts unset.
            _caretUnitBoundaryCacheOffset = -1;
        } 
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        // Creates a new undo unit instance.
        internal TextTreeExtractElementUndoUnit(TextContainer tree, TextTreeTextElementNode elementNode)
            : base(tree, elementNode.GetSymbolOffset(tree.Generation))
        {
            _symbolCount = elementNode.SymbolCount;
            _type = elementNode.TextElement.GetType();
            _localValues = GetPropertyRecordArray(elementNode.TextElement);
            _resources = elementNode.TextElement.Resources;

            // Table requires additional work for storing its Columns collection
            if (elementNode.TextElement is Table)
            {
                _columns = TextTreeDeleteContentUndoUnit.SaveColumns((Table)elementNode.TextElement);
            }
        }
        //------------------------------------------------------
        //
        //  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);
        }
        // Adds a DeleteContentUndoUnit to the open parent undo unit, if any.
        // Called by TextContainer.DeleteContent.
        internal static TextTreeDeleteContentUndoUnit CreateDeleteContentUndoUnit(TextContainer tree, TextPointer start, TextPointer end)
        {
            UndoManager undoManager;
            TextTreeDeleteContentUndoUnit undoUnit;

            if (start.CompareTo(end) == 0)
                return null;

            undoManager = GetOrClearUndoManager(tree);
            if (undoManager == null)
                return null;

            undoUnit = new TextTreeDeleteContentUndoUnit(tree, start, end);

            undoManager.Add(undoUnit);

            return undoUnit;
        }
Example #9
0
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        #region Internal Methods

        // Attaches this control to a new TextContainer.
        internal void InitializeTextContainer(TextContainer textContainer)
        {
            Invariant.Assert(textContainer != null);
            Invariant.Assert(textContainer.TextSelection == null);

            // Uninitialize previous TextEditor
            if (_textContainer != null)
            {
                Invariant.Assert(_textEditor != null);
                Invariant.Assert(_textEditor.TextContainer == _textContainer);
                Invariant.Assert(_textEditor.TextContainer.TextSelection == _textEditor.Selection);

                // Detach existing editor from VisualTree
                DetachFromVisualTree();

                // Discard TextEditor - must release text container
                _textEditor.OnDetach();
            }

            // Save text container
            _textContainer = textContainer;
            _textContainer.Changed += new TextContainerChangedEventHandler(OnTextContainerChanged);

            // Create a text editor, initialize undo manager for it, and link it to text container
            _textEditor = new TextEditor(_textContainer, this, true);
            _textEditor.Selection.Changed += new EventHandler(OnSelectionChangedInternal);

            // Init a default undo limit.
            UndoManager undoManager = UndoManager.GetUndoManager(this);
            if (undoManager != null)
            {
                undoManager.UndoLimit = this.UndoLimit;
            }

            // Delay raising automation events until the automation subsystem is activated by a client.
            // ISSUE-2005/01/23-vsmirnov - Adding an event listener to AutomationProvider apparently
            // causes memory leaks because TextBoxBase is never released. I comment it out for now just
            // to fix the build break (perf DRT failure). Need to find a right fix later.
            // AutomationProvider.Activated += new AutomationActivatedEventHandler(OnAutomationActivated);
        }
Example #10
0
        /// <summary>
        /// Constructor
        /// </summary>
        public TextBox() : base()
        {
            // Register static editing command handlers.
            // This only has an effect that first time we make the call.
            // We don't use the static ctor because there are cases
            // where another control will want to alias our properties
            // but doesn't need this overhead.
            TextEditor.RegisterCommandHandlers(typeof(TextBox), /*acceptsRichContent:*/false, /*readOnly*/false, /*registerEventListeners*/false);

            // Create TextContainer and TextEditor associated with it
            TextContainer container = new TextContainer(this, true /* plainTextOnly */);
            container.CollectTextChanges = true;
            InitializeTextContainer(container);

            // TextBox only accepts plain text, so change TextEditor's default to that.
            this.TextEditor.AcceptsRichContent = false;
        }
Example #11
0
        // Positions this navigator at a node/edge pair.
        // Node/edge are adjusted based on the current gravity.
        private void MoveToNode(TextContainer tree, TextTreeNode node, ElementEdge edge)
        {
            RepositionForGravity(ref node, ref edge, GetGravityInternal());

            _tree = tree;
            SetNodeAndEdge(AdjustRefCounts(node, edge, _node, this.Edge), edge);
            _generation = tree.PositionGeneration;
        }
Example #12
0
        // Does a deep extract of all top-level TextElements between two positions. 
        // Returns the combined symbol count of all extracted elements.
        // Each extracted element (and its children) are moved into a private tree. 
        // This insures that outside references to the TextElement can still use
        // the TextElements freely, inserting or removing content, etc.
        //
        // Also calls AddLogicalChild on any top-level UIElements encountered. 
        private int CutTopLevelLogicalNodes(TextTreeNode containingNode, TextPointer startPosition, TextPointer endPosition, out int charCount)
        { 
            SplayTreeNode node; 
            SplayTreeNode nextNode;
            SplayTreeNode stopNode; 
            TextTreeTextElementNode elementNode;
            TextTreeObjectNode uiElementNode;
            char[] elementText;
            int symbolCount; 
            TextContainer tree;
            TextPointer newTreeStart; 
            DependencyObject logicalParent; 
            object currentLogicalChild;
 
            Invariant.Assert(startPosition.GetScopingNode() == endPosition.GetScopingNode(), "startPosition/endPosition not in same sibling tree!");

            node = startPosition.GetAdjacentSiblingNode(LogicalDirection.Forward);
            stopNode = endPosition.GetAdjacentSiblingNode(LogicalDirection.Forward); 

            symbolCount = 0; 
            charCount = 0; 

            logicalParent = containingNode.GetLogicalTreeNode(); 

            while (node != stopNode)
            {
                currentLogicalChild = null; 

                // Get the next node now, before we extract any TextElementNodes. 
                nextNode = node.GetNextNode(); 

                elementNode = node as TextTreeTextElementNode; 
                if (elementNode != null)
                {
                    // Grab the IMECharCount before we modify the node.
                    // This value depends on the node's current context. 
                    int imeCharCountInOriginalContainer = elementNode.IMECharCount;
 
                    // Cut and record the matching symbols. 
                    elementText = TextTreeText.CutText(_rootNode.RootTextBlock, elementNode.GetSymbolOffset(this.Generation), elementNode.SymbolCount);
 
                    // Rip the element out of its sibling tree.
                    // textElementNode.TextElement's TextElementNode will be updated
                    // with a deep copy of all contained nodes. We need a deep copy
                    // to ensure the new element/tree has no TextPointer references. 
                    ExtractElementFromSiblingTree(containingNode, elementNode, true /* deep */);
                    // Assert that the TextElement now points to a new TextElementNode, not the original one. 
                    Invariant.Assert(elementNode.TextElement.TextElementNode != elementNode); 
                    // We want to start referring to the copied node, update elementNode.
                    elementNode = elementNode.TextElement.TextElementNode; 

                    UpdateContainerSymbolCount(containingNode, -elementNode.SymbolCount, -imeCharCountInOriginalContainer);
                    NextGeneration(true /* deletedContent */);
 
                    // Stick it in a private tree so it's safe for the outside world to play with.
                    tree = new TextContainer(null, false /* plainTextOnly */); 
                    newTreeStart = tree.Start; 

                    tree.InsertElementToSiblingTree(newTreeStart, newTreeStart, elementNode); 
                    Invariant.Assert(elementText.Length == elementNode.SymbolCount);
                    tree.UpdateContainerSymbolCount(elementNode.GetContainingNode(), elementNode.SymbolCount, elementNode.IMECharCount);
                    tree.DemandCreateText();
                    TextTreeText.InsertText(tree.RootTextBlock, 1 /* symbolOffset */, elementText); 
                    tree.NextGeneration(false /* deletedContent */);
 
                    currentLogicalChild = elementNode.TextElement; 

                    // Keep a running total of how many symbols we've removed. 
                    symbolCount += elementNode.SymbolCount;
                    charCount += imeCharCountInOriginalContainer;
                }
                else 
                {
                    uiElementNode = node as TextTreeObjectNode; 
                    if (uiElementNode != null) 
                    {
                        currentLogicalChild = uiElementNode.EmbeddedElement; 
                    }
                }

                // Remove the child from the logical tree 
                LogicalTreeHelper.RemoveLogicalChild(logicalParent, currentLogicalChild);
 
                node = nextNode; 
            }
 
            if (symbolCount > 0)
            {
                startPosition.SyncToTreeGeneration();
                endPosition.SyncToTreeGeneration(); 
            }
 
            return symbolCount; 
        }
Example #13
0
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        // Create a new undo unit instance.
        internal TextTreeUndoUnit(TextContainer tree, int symbolOffset)
        {
            _tree = tree;
            _symbolOffset = symbolOffset;
            _treeContentHashCode = _tree.GetContentHashCode();
        }
Example #14
0
            //------------------------------------------------------
            // 
            //  Constructors
            //
            //-----------------------------------------------------
 
            #region Constructors
 
            // Creates a new instance. 
            internal ExtractChangeEventArgs(TextContainer textTree, TextPointer startPosition, TextTreeTextElementNode node,
                TextTreeTextElementNode newFirstIMEVisibleNode, TextTreeTextElementNode formerFirstIMEVisibleNode, int charCount, int childCharCount) 
            {
                _textTree = textTree;
                _startPosition = startPosition;
                _symbolCount = node.SymbolCount; 
                _charCount = charCount;
                _childCharCount = childCharCount; 
                _newFirstIMEVisibleNode = newFirstIMEVisibleNode; 
                _formerFirstIMEVisibleNode = formerFirstIMEVisibleNode;
            } 
Example #15
0
        // ------------------------------------------------------------------
        // Make sure that complex content is enabled.
        // ------------------------------------------------------------------
        private void EnsureComplexContent(ITextContainer textContainer)
        {
            if (_complexContent == null)
            {
                if (textContainer == null)
                {
                    textContainer = new TextContainer(IsContentPresenterContainer ? null : this, false /* plainTextOnly */);
                }

                _complexContent = new ComplexContent(this, textContainer, false, Text);
                _contentCache = null;

                if (CheckFlags(Flags.FormattedOnce))
                {
                    // If we've already measured at least once, hook up the TextContainer
                    // listeners now.
                    Invariant.Assert(!CheckFlags(Flags.PendingTextContainerEventInit));
                    InitializeTextContainerListeners();

                    // Line layout data cached up to this point will become invalid
                    // becasue of content structure change (implicit Run added).
                    // So we need to clear the cache - we call InvalidateMeasure for this
                    // purpose. However, we do not want to produce a side effect
                    // of making layout invalid as a result of touching ContentStart/ContentEnd
                    // and other properties. For that we need to UpdateLayout when it was
                    // dirtied by our switch.
                    bool wasLayoutValid = this.IsMeasureValid && this.IsArrangeValid;
                    InvalidateMeasure();
                    InvalidateVisual(); //ensure re-rendering too
                    if (wasLayoutValid)
                    {
                        UpdateLayout();
                    }
                }
                else
                {
                    // Otherwise, wait until our first measure.
                    // This lets us skip the work for all content invalidation
                    // during load, before the first measure.
                    SetFlags(true, Flags.PendingTextContainerEventInit);
                }
            }
        }
 /// <summary>
 /// FlowDocument constructor with TextContainer.
 /// </summary>
 internal FlowDocument(TextContainer textContainer)
     : base()
 {
     Initialize(textContainer);
 }
Example #17
0
        // Called by the TextPointer ctor.  Initializes this instance.
        private void Initialize(TextContainer tree, TextTreeNode node, ElementEdge edge, LogicalDirection gravity, uint generation,
            bool caretUnitBoundaryCache, bool isCaretUnitBoundaryCacheValid, uint layoutGeneration)
        {
            _tree = tree;

            // Fixup of the target node based on gravity.
            // Positions always cling to a node edge that matches their gravity,
            // so that insert ops never affect the position.
            RepositionForGravity(ref node, ref edge, gravity);

            SetNodeAndEdge(node.IncrementReferenceCount(edge), edge);
            _generation = generation;

            this.CaretUnitBoundaryCache = caretUnitBoundaryCache;
            this.IsCaretUnitBoundaryCacheValid = isCaretUnitBoundaryCacheValid;
            _layoutGeneration = layoutGeneration;

            VerifyFlags();
            tree.AssertTree();
            AssertState();
        }
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        // Creates a new undo unit instance.
        // symbolOffset should be just before the start edge of the TextElement to remove.
        // If deep is true, this unit will undo not only the scoping element
        // insert, but also all content scoped by the element.
        internal TextTreeInsertElementUndoUnit(TextContainer tree, int symbolOffset, bool deep) : base(tree, symbolOffset)
        {
            _deep = deep;
        }
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        // Create a new undo unit instance.
        // symbolOffset and symbolCount track the offset of the inserted content
        // and its symbol count, respectively.
        internal TextTreeInsertUndoUnit(TextContainer tree, int symbolOffset, int symbolCount) : base(tree, symbolOffset)
        {
            Invariant.Assert(symbolCount > 0, "Creating no-op insert undo unit!");

            _symbolCount = symbolCount;
        }
 /// <summary>
 /// CreateTextBlock - Creates a text block, adds as visual child, databinds properties and sets up appropriate event listener.
 /// </summary>
 private void CreateTextBlock()
 {
     _textContainer = new TextContainer(this, false /* plainTextOnly */);
     _textBlock = new TextBlock();
     AddVisualChild(_textBlock);
     _textBlock.IsContentPresenterContainer = true;
     _textBlock.SetTextContainer(_textContainer);
     InitializeTextContainerListener();
 }
Example #21
0
        // Creates a new TextPointer instance.
        internal TextPointer(TextContainer textContainer, int offset, LogicalDirection direction)
        {
            SplayTreeNode node;
            ElementEdge edge;

            if (offset < 1 || offset > textContainer.InternalSymbolCount - 1)
            {
                throw new ArgumentException(SR.Get(SRID.BadDistance));
            }

            textContainer.GetNodeAndEdgeAtOffset(offset, out node, out edge);

            Initialize(textContainer, (TextTreeNode)node, edge, direction, textContainer.PositionGeneration, false, false, textContainer.LayoutGeneration);
        }
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        // Create a new undo unit instance.
        // symbolOffset is where property values will be set.
        internal TextTreePropertyUndoUnit(TextContainer tree, int symbolOffset, PropertyRecord propertyRecord) : base(tree, symbolOffset)
        {
            _propertyRecord = propertyRecord;
        }
        /// <summary>
        /// Initialize FlowDocument.
        /// </summary>
        /// <param name="textContainer"></param>
        private void Initialize(TextContainer textContainer)
        {
            if (textContainer == null)
            {
                // Create text tree that contains content of the element.
                textContainer = new TextContainer(this, false /* plainTextOnly */);
            }

            // Create structural cache object
            _structuralCache = new StructuralCache(this, textContainer);

            // Get rid of the current formatter.
            if (_formatter != null)
            {
                _formatter.Suspend();
                _formatter = null;
            }
        }
Example #24
0
        // Returns the symbol offset within the TextContainer of this Position.
        internal static int GetSymbolOffset(TextContainer tree, TextTreeNode node, ElementEdge edge)
        {
            int offset;

            switch (edge)
            {
                case ElementEdge.BeforeStart:
                    offset = node.GetSymbolOffset(tree.Generation);
                    break;

                case ElementEdge.AfterStart:
                    offset = node.GetSymbolOffset(tree.Generation) + 1;
                    break;

                case ElementEdge.BeforeEnd:
                    offset = node.GetSymbolOffset(tree.Generation) + node.SymbolCount - 1;
                    break;

                case ElementEdge.AfterEnd:
                    offset = node.GetSymbolOffset(tree.Generation) + node.SymbolCount;
                    break;

                default:
                    Invariant.Assert(false, "Unknown value for position edge");
                    offset = 0;
                    break;
            }

            return offset;
        }
        // Demand creates a TextContainer if no tree is associated with this instance.
        // Otherwise returns the exisiting tree, and clears the tree's DeadPositionList.
        private TextContainer EnsureTextContainer()
        {
            TextContainer tree;
            TextPointer start;

            if (this.IsInTree)
            {
                tree = _textElementNode.GetTextTree();
                tree.EmptyDeadPositionList();
            }
            else
            {
                tree = new TextContainer(null, false /* plainTextOnly */);
                start = tree.Start;

                tree.BeginChange();
                try
                {
                    tree.InsertElementInternal(start, start, this);
                }
                finally
                {
                    // No event will be raised, since we know there are no listeners yet!
                    tree.EndChange();
                }

                Invariant.Assert(this.IsInTree);
            }

            return tree;
        }
Example #26
0
 // Creates a new TextPointer instance.
 internal TextPointer(TextContainer tree, TextTreeNode node, ElementEdge edge, LogicalDirection direction)
 {
     Initialize(tree, node, edge, direction, tree.PositionGeneration, false, false, tree.LayoutGeneration);
 }
        // Adds a TextTreeExtractElementUndoUnit to the open parent undo unit, if any.
        // Called by TextContainer.ExtractElement.
        internal static TextTreeExtractElementUndoUnit CreateExtractElementUndoUnit(TextContainer tree, TextTreeTextElementNode elementNode)
        {
            UndoManager undoManager;
            TextTreeExtractElementUndoUnit undoUnit;

            undoManager = GetOrClearUndoManager(tree);
            if (undoManager == null)
                return null;

            undoUnit = new TextTreeExtractElementUndoUnit(tree, elementNode);

            undoManager.Add(undoUnit);

            return undoUnit;
        }
Example #28
0
        internal static int GetTextInRun(TextContainer textContainer, int symbolOffset, TextTreeTextNode textNode, int nodeOffset, LogicalDirection direction, char[] textBuffer, int startIndex, int count)
        {
            int skipCount;
            int finalCount;

            if (textBuffer == null)
            {
                throw new ArgumentNullException("textBuffer");
            }
            if (startIndex < 0)
            {
                throw new ArgumentException(SR.Get(SRID.NegativeValue, "startIndex"));
            }
            if (startIndex > textBuffer.Length)
            {
                throw new ArgumentException(SR.Get(SRID.StartIndexExceedsBufferSize, startIndex, textBuffer.Length));
            }
            if (count < 0)
            {
                throw new ArgumentException(SR.Get(SRID.NegativeValue, "count"));
            }
            if (count > textBuffer.Length - startIndex)
            {
                throw new ArgumentException(SR.Get(SRID.MaxLengthExceedsBufferSize, count, textBuffer.Length, startIndex));
            }
            Invariant.Assert(textNode != null, "textNode is expected to be non-null");

            textContainer.EmptyDeadPositionList();

            if (nodeOffset < 0)
            {
                skipCount = 0;
            }
            else
            {
                skipCount = (direction == LogicalDirection.Forward) ? nodeOffset : textNode.SymbolCount - nodeOffset;
                symbolOffset += nodeOffset;
            }
            finalCount = 0;

            // Loop and combine adjacent text nodes into a single run.
            // This isn't just a perf optimization.  Because text positions
            // split text nodes, if we just returned a single node's text
            // callers would see strange side effects where position.GetTextLength() !=
            // position.GetText() if another position is moved between the calls.
            while (textNode != null)
            {
                // Never return more textBuffer than the text following this position in the current text node.
                finalCount += Math.Min(count - finalCount, textNode.SymbolCount - skipCount);
                skipCount = 0;
                if (finalCount == count)
                    break;
                textNode = ((direction == LogicalDirection.Forward) ? textNode.GetNextNode() : textNode.GetPreviousNode()) as TextTreeTextNode;
            }

            // If we're reading backwards, need to fixup symbolOffset to point into the node.
            if (direction == LogicalDirection.Backward)
            {
                symbolOffset -= finalCount;
            }

            if (finalCount > 0) // We may not have allocated textContainer.RootTextBlock if no text was ever inserted.
            {
                TextTreeText.ReadText(textContainer.RootTextBlock, symbolOffset, finalCount, textBuffer, startIndex);
            }

            return finalCount;
        }