Ejemplo n.º 1
0
        /// <summary>
        /// Insert paragraph break at the End position of a range. 
        /// It only affects specified position - not a whole range.
        /// So it is essentially TextContainer-level (low-level) operation.
        /// </summary>
        /// <param name="position"> 
        /// Position at which the content should be split into two paragraphs.
        /// After the operation breakPosition moved into a beginning of the 
        /// second paragraph after all opening tags created by splitting 
        /// (this position may be not-normalized though if there are some
        /// other opening formatting tags following the position - this may 
        /// be important for reading from xml when pasting point was before
        /// some opening formatting tags but after non-whitespace characters).
        /// </param>
        /// <param name="moveIntoSecondParagraph"> 
        /// True means that resulting TextPointer must be moved into the second paragraph.
        /// False means that resulting pointer remains in a non-normalized position 
        /// between two paragraphs (or list items). 
        /// </param>
        /// <remarks> 
        /// This function could be implemented from TextContainer class.
        /// </remarks>
        /// <returns>
        /// If position passed was in paragraph content, returns a TextPointer 
        /// at an ContentStart of the second paragraph.
        /// If position passed was at a structural boundary (specifically table row end, 
        /// block ui container start/end or before first table in a collection of blocks), 
        /// then an implicit paragraph is inserted at the boundary and a position at its
        /// ContentStart is returned. 
        /// </returns>
        internal static TextPointer InsertParagraphBreak(TextPointer position, bool moveIntoSecondParagraph)
        {
            Invariant.Assert(position.TextContainer.Parent == null || TextSchema.IsValidChildOfContainer(position.TextContainer.Parent.GetType(), typeof(Paragraph))); 

            bool structuralBoundaryCrossed = TextPointerBase.IsAtRowEnd(position) || 
                TextPointerBase.IsBeforeFirstTable(position) || 
                TextPointerBase.IsInBlockUIContainer(position);
 
            if (position.Paragraph == null)
            {
                // Ensure insertion position, in case original position is not in text content.
                position = TextRangeEditTables.EnsureInsertionPosition(position); 
            }
 
            Inline ancestor = position.GetNonMergeableInlineAncestor(); 
            if (ancestor != null)
            { 
                Invariant.Assert(TextPointerBase.IsPositionAtNonMergeableInlineBoundary(position), "Position must be at hyperlink boundary!");

                // If position is at a hyperlink boundary, move outside hyperlink element scope
                // so that we can successfuly split formatting elements upto paragraph ancestor. 

                position = position.IsAtNonMergeableInlineStart ? ancestor.ElementStart : ancestor.ElementEnd; 
            } 

            Paragraph paragraph = position.Paragraph; 
            if (paragraph == null)
            {
                // At this point, we expect we're working in a fragment of Inlines only.
                Invariant.Assert(position.TextContainer.Parent == null); 

                // Add a parent Paragraph to split. 
                paragraph = new Paragraph(); 
                paragraph.Reposition(position.DocumentStart, position.DocumentEnd);
            } 

            if (structuralBoundaryCrossed)
            {
                // In case structural boundary was crossed, an implicit paragraph was inserted in EnsureInsertionPosition. 
                // No need to insert another paragraph break.
                return position; 
            } 

            TextPointer breakPosition = position; 

            // Split all inline elements up to this paragraph
            breakPosition = SplitFormattingElements(breakPosition, /*keepEmptyFormatting:*/true);
            Invariant.Assert(breakPosition.Parent == paragraph, "breakPosition must be in paragraph scope after splitting formatting elements"); 

            // Decide whether we need to split ListItem around this paragraph (if any). 
            // We are splitting a list item if this paragraph is the only paragraph in a list item. 
            // Otherwise we simply produce new paragraphs within the same list item.
            bool needToSplitListItem = TextPointerBase.GetImmediateListItem(paragraph.ContentStart) != null; 

            breakPosition = SplitElement(breakPosition);

            // Also split ListItem (if any) 
            if (needToSplitListItem)
            { 
                Invariant.Assert(breakPosition.Parent is ListItem, "breakPosition must be in ListItem scope"); 
                breakPosition = SplitElement(breakPosition);
            } 

            if (moveIntoSecondParagraph)
            {
                // Move breakPosition inside of the second paragraph 
                while (!(breakPosition.Parent is Paragraph) && breakPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart)
                { 
                    breakPosition = breakPosition.GetNextContextPosition(LogicalDirection.Forward); 
                }
 
                // Normalize with forward gravity
                breakPosition = breakPosition.GetInsertionPosition(LogicalDirection.Forward);
            }
 
            return breakPosition;
        } 
Ejemplo n.º 2
0
        // Helper for EnsureInsertionPosition, inserts a Paragraph element with a single Run at this position. 
        private static TextPointer CreateImplicitParagraph(TextPointer position)
        { 
            TextPointer insertionPosition;

            Paragraph implicitParagraph = new Paragraph();
            implicitParagraph.Reposition(position, position); 
            Run implicitRun = Run.CreateImplicitRun(implicitParagraph);
            implicitParagraph.Inlines.Add(implicitRun); 
            insertionPosition = implicitRun.ContentStart.GetFrozenPointer(position.LogicalDirection); // return a position with the same orientation inside a Run 

            return insertionPosition; 
        }