Example #1
0
        // Apply typing heuristics
        //  - extend for overtype. 
        //  - prevent paragraph merges when only the leading edge of that 
        //    last paragraph is selected.
        // 
        // ApplyInitialTypingHeuristics/ApplyFinalTypingHeuristics are
        // called together, with a an extra step in between for TextSelection
        // overrides of the ApplyTypingHueristic method.
        internal static void ApplyFinalTypingHeuristics(ITextRange thisRange, bool overType) 
        {
            // Expand empty selection forward in overtype mode 
            if (overType && thisRange.IsEmpty && 
                !TextPointerBase.IsNextToAnyBreak(thisRange.End, LogicalDirection.Forward))
            { 
                //


                ITextPointer nextPosition = thisRange.End.CreatePointer(); 
                nextPosition.MoveToNextInsertionPosition(LogicalDirection.Forward);
                if (!TextRangeEditTables.IsTableStructureCrossed(thisRange.Start, nextPosition)) 
                { 
                    TextRange range = new TextRange(thisRange.Start, nextPosition);
                    Invariant.Assert(!range.IsTableCellRange); 

                    range.Text = String.Empty;
                }
            } 

            // If the range is non-empty, and its end just passes a paragraph break, 
            // pull the end back to stop a paragraph merge on the next keystroke. 
            if (!thisRange.IsEmpty &&
                (TextPointerBase.IsNextToAnyBreak(thisRange.End, LogicalDirection.Backward) || 
                 TextPointerBase.IsAfterLastParagraph(thisRange.End)))
            {
                ITextPointer newEnd = thisRange.End.GetNextInsertionPosition(LogicalDirection.Backward);
                thisRange.Select(thisRange.Start, newEnd); 
            }
        } 
Example #2
0
        // Implementation of a setter fot ITextRange.Text property
        internal static void SetText(ITextRange thisRange, string textData) 
        {
            NormalizeRange(thisRange); 
 
            if (textData == null)
            { 
                throw new ArgumentNullException("textData");
            }

            ITextPointer explicitInsertPosition = null; 

            TextRangeBase.BeginChange(thisRange); 
            try 
            {
                // Delete content covered by this range 
                if (!thisRange.IsEmpty)
                {
                    if (thisRange.Start is TextPointer &&
                        ((TextPointer)thisRange.Start).Parent == ((TextPointer)thisRange.End).Parent && 
                        ((TextPointer)thisRange.Start).Parent is Run &&
                        textData.Length > 0) 
                    { 
                        // When textrange start/end are parented by the same Run, we can optimize
                        // and delete content without any checks. 
                        //
                        // Note that NOT doing so has a serious side effect in this case.
                        // Low-level code in TextRangeEdit does not preserve an empty run
                        // with no formatting properties after deletion. 
                        // We dont want to loose the empty Run,
                        // when we are just about to set the range text to non-empty string. 
                        // Otherwise, newly inserted text might have undesirable formatting properties 
                        // applied due to an insertion position within an adjacent Run.
 
                        if (thisRange.Start.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text &&
                            thisRange.End.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
                        {
                            // If we're deleting with surrounding text, make sure we insert later between the surrounding text. 
                            // Because we will invalidate layout with the delete, it's possible that thisRange.Start
                            // will normalize itself to a different character offset on the next reference. 
                            // This is because -- unfortunately -- when layout is valid we use ITextView.IsAtCaretUnitBoundary 
                            // to normalize unicode offsets, but when layout is dirty we use a different code path
                            // that ignores the current font and simply checks Unicode values for surrogates and 
                            // combining marks.  See bug 1683515 for an example.
                            explicitInsertPosition = thisRange.Start;
                        }
 
                        TextContainer textContainer = ((TextPointer)thisRange.Start).TextContainer;
                        textContainer.DeleteContentInternal((TextPointer)thisRange.Start, (TextPointer)thisRange.End); 
                    } 
                    else
                    { 
                        thisRange.Start.DeleteContentToPosition(thisRange.End);
                    }

                    if (thisRange.Start is TextPointer) 
                    {
                        TextRangeEdit.MergeFlowDirection((TextPointer)thisRange.Start); 
                    } 

                    thisRange.Select(thisRange.Start, thisRange.Start); 
                }

                // Insert text at end position
                // Note that the non-emptiness check below is not an optimization: 
                // In case of empty text the code block in it would change an empty range
                // orientation, which is undesirable side effect. 
                // Also if the inserted text is empty we need to avoid ensuring insertion position, 
                // which can create paragraphs etc.
                if (textData.Length > 0) 
                {
                    ITextPointer insertPosition = (explicitInsertPosition == null) ? thisRange.Start : explicitInsertPosition;

                    // Ensure last paragraph existence and prepare ends for the new selection 
                    bool pastedFragmentEndsWithNewLine = textData.EndsWith("\n", StringComparison.Ordinal);
 
                    // We are going to insert paragraph implicitly when the block content becomes totally empty. 
                    // Store the fact that implicit paragraph was inserted to exclude ane extra paragraph break
                    // from the end of pasted fragment 
                    bool implicitParagraphInserted = insertPosition is TextPointer &&
                        TextSchema.IsValidChild(/*position*/insertPosition, /*childType*/typeof(Block)) &&
                        (insertPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.None ||
                        insertPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart) && 
                        (insertPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.None ||
                        insertPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd); 
 
                    // Make sure that the range is positioned at insertion position
                    if (insertPosition is TextPointer && explicitInsertPosition == null) 
                    {
                        TextPointer insertionPosition = TextRangeEditTables.EnsureInsertionPosition((TextPointer)insertPosition);
                        thisRange.Select(insertionPosition, insertionPosition);
                        insertPosition = thisRange.Start; 
                    }
                    Invariant.Assert(TextSchema.IsInTextContent(insertPosition), "range.Start is expected to be in text content"); 
 
                    ITextPointer newStart = insertPosition.GetFrozenPointer(LogicalDirection.Backward);
                    ITextPointer newEnd = insertPosition.CreatePointer(LogicalDirection.Forward); 

                    if ((newStart is TextPointer) && ((TextPointer)newStart).Paragraph != null)
                    {
                        // Rich text - '\n' must be replaced by Paragraphs 
                        TextPointer insertionPosition = (TextPointer)newStart.CreatePointer(LogicalDirection.Forward);
                        string[] textParagraphs = textData.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); 
 
                        int length = textParagraphs.Length;
                        if (implicitParagraphInserted && pastedFragmentEndsWithNewLine) 
                        {
                            length--;
                        }
 
                        for (int i = 0; i < length; i++)
                        { 
                            insertionPosition.InsertTextInRun(textParagraphs[i]); 
                            if (i < length - 1)
                            { 
                                if (insertionPosition.HasNonMergeableInlineAncestor)
                                {
                                    // We cannot split a Hyperlink or other non-mergeable Inline element,
                                    // so insert a space character instead (similar to embedded object). 
                                    // Note that this means, SetText would loose
                                    // paragraph break information in this case. 
                                    insertionPosition.InsertTextInRun(" "); 
                                }
                                else 
                                {
                                    // insertionPosition gets repositioned to just inside
                                    // the following Paragraph.
                                    insertionPosition = insertionPosition.InsertParagraphBreak(); 
                                }
                                // Keep newEnd in [....] with the paragraph break. 
                                // We can't rely on LogicalDirection alone for 
                                // anything other than simple text inserts.
                                newEnd = insertionPosition; 
                            }
                        }

                        if (implicitParagraphInserted && pastedFragmentEndsWithNewLine) 
                        {
                            // We must include ending paragraph break into a resulting range 
                            newEnd = newEnd.GetNextInsertionPosition(LogicalDirection.Forward); 
                            if (newEnd == null)
                            { 
                                newEnd = newStart.TextContainer.End; // set end of range to IsAfterLastParagraph position
                            }

                            // Note: As a result of this logic with implicitParagraphInserted && pastedFragmentEndsWithNewLine 
                            // we have the following behavior:
                            // Given that: 
                            //    range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd); 
                            // the statement:
                            //    range.Text = "foo\r\n"; 
                            // has the effect of leaving flowDocument with this content (note: just one paragraph):
                            //    <Paragraph>foo</Paragraph>
                            // and range selecting the whole content:
                            //    range.Text == "foo\r\n" 
                            //
                            // the statement: 
                            //    range.Text = "foo"; 
                            // results with the same content in flowDocument (one paragraph)
                            // but the range is not extended beyond last paragraph end: 
                            //    range.Text == "foo".
                        }
                    }
                    else 
                    {
                        // Non-paragraph text - insert without '\n' conversion 
                        newStart.InsertTextInRun(textData); 
                    }
 
                    // Select the range
                    TextRangeBase.SelectPrivate(thisRange, newStart, newEnd, /*includeCellAtMovingPosition:*/false, /*markRangeChanged*/true);
                }
            } 
            finally
            { 
                TextRangeBase.EndChange(thisRange); 
            }
        } 
Example #3
0
 // Apply initial typing heuristics -- adjust range for typing 
 // when it spans one or more TableCells.
 // 
 // ApplyInitialTypingHeuristics/ApplyFinalTypingHeuristics are
 // called together, with a an extra step in between for TextSelection
 // overrides of the ApplyTypingHueristic method.
 internal static void ApplyInitialTypingHeuristics(ITextRange thisRange) 
 {
     // When table cells selected, clear the start cell and collapse selection into it 
     if (thisRange.IsTableCellRange) 
     {
         TableCell cell; 
         if (thisRange.Start is TextPointer &&
             (cell = TextRangeEditTables.GetTableCellFromPosition((TextPointer)thisRange.Start)) != null)
         {
             // Select the first cell content to make springload formatting happen below 
             thisRange.Select(cell.ContentStart, cell.ContentEnd);
         } 
         else 
         {
             thisRange.Select(thisRange.Start, thisRange.Start); 
         }
     }
 }
        internal static ITextRange Find(FindToolBar findToolBar, TextEditor textEditor, ITextView textView, ITextView masterPageTextView)
        {
            ITextPointer textPointer = null;

            Invariant.Assert(findToolBar != null);
            Invariant.Assert(textEditor != null);
            FindFlags findFlags = FindFlags.None;

            findFlags |= (findToolBar.SearchUp ? FindFlags.FindInReverse : FindFlags.None);
            findFlags |= (findToolBar.MatchCase ? FindFlags.MatchCase : FindFlags.None);
            findFlags |= (findToolBar.MatchWholeWord ? FindFlags.FindWholeWordsOnly : FindFlags.None);
            findFlags |= (findToolBar.MatchDiacritic ? FindFlags.MatchDiacritics : FindFlags.None);
            findFlags |= (findToolBar.MatchKashida ? FindFlags.MatchKashida : FindFlags.None);
            findFlags |= (findToolBar.MatchAlefHamza ? FindFlags.MatchAlefHamza : FindFlags.None);
            ITextContainer textContainer       = textEditor.TextContainer;
            ITextRange     selection           = textEditor.Selection;
            string         searchText          = findToolBar.SearchText;
            CultureInfo    documentCultureInfo = DocumentViewerHelper.GetDocumentCultureInfo(textContainer);
            ITextPointer   textPointer2;
            ITextPointer   textPointer3;
            ITextRange     textRange;

            if (selection.IsEmpty)
            {
                if (textView != null && !textView.IsValid)
                {
                    textView = null;
                }
                if (textView != null && textView.Contains(selection.Start))
                {
                    textPointer2 = (findToolBar.SearchUp ? textContainer.Start : selection.Start);
                    textPointer3 = (findToolBar.SearchUp ? selection.Start : textContainer.End);
                }
                else
                {
                    if (masterPageTextView != null && masterPageTextView.IsValid)
                    {
                        foreach (TextSegment textSegment in masterPageTextView.TextSegments)
                        {
                            if (!textSegment.IsNull)
                            {
                                if (textPointer == null)
                                {
                                    textPointer = ((!findToolBar.SearchUp) ? textSegment.Start : textSegment.End);
                                }
                                else if (!findToolBar.SearchUp)
                                {
                                    if (textSegment.Start.CompareTo(textPointer) < 0)
                                    {
                                        textPointer = textSegment.Start;
                                    }
                                }
                                else if (textSegment.End.CompareTo(textPointer) > 0)
                                {
                                    textPointer = textSegment.End;
                                }
                            }
                        }
                    }
                    if (textPointer != null)
                    {
                        textPointer2 = (findToolBar.SearchUp ? textContainer.Start : textPointer);
                        textPointer3 = (findToolBar.SearchUp ? textPointer : textContainer.End);
                    }
                    else
                    {
                        textPointer2 = textContainer.Start;
                        textPointer3 = textContainer.End;
                    }
                }
            }
            else
            {
                textRange = TextFindEngine.Find(selection.Start, selection.End, searchText, findFlags, documentCultureInfo);
                if (textRange != null && textRange.Start != null && textRange.Start.CompareTo(selection.Start) == 0 && textRange.End.CompareTo(selection.End) == 0)
                {
                    textPointer2 = (findToolBar.SearchUp ? selection.Start : selection.End);
                    textPointer3 = (findToolBar.SearchUp ? textContainer.Start : textContainer.End);
                }
                else
                {
                    textPointer2 = (findToolBar.SearchUp ? selection.End : selection.Start);
                    textPointer3 = (findToolBar.SearchUp ? textContainer.Start : textContainer.End);
                }
            }
            textRange = null;
            if (textPointer2 != null && textPointer3 != null && textPointer2.CompareTo(textPointer3) != 0)
            {
                if (textPointer2.CompareTo(textPointer3) > 0)
                {
                    ITextPointer textPointer4 = textPointer2;
                    textPointer2 = textPointer3;
                    textPointer3 = textPointer4;
                }
                textRange = TextFindEngine.Find(textPointer2, textPointer3, searchText, findFlags, documentCultureInfo);
                if (textRange != null && !textRange.IsEmpty)
                {
                    selection.Select(textRange.Start, textRange.End);
                }
            }
            return(textRange);
        }