CompareTo() 공개 메소드

public CompareTo ( TextPointer position ) : int
position TextPointer
리턴 int
예제 #1
0
        //---------------------------
        // public static methods
        //---------------------------
        
        /// <summary>
        /// resolves text effect on a text range to a list of text effect targets.
        /// The method will walk the text and perform the following task:
        /// 1) For each continous block of text, create a text effect targeting the scoping element
        /// 2) For the text effect created, calculate the starting cp index and cp count for the effect
        /// 
        /// The method will create freezable copy of the TextEffect passed in and fill in 
        /// CharacterIndex and Count for the range.
        /// </summary>
        /// <param name="startPosition">starting text pointer</param>
        /// <param name="endPosition">end text pointer</param>
        /// <param name="effect">effect that is apply on the text</param>
        public static TextEffectTarget[] Resolve(
            TextPointer             startPosition, 
            TextPointer             endPosition,
            TextEffect              effect
            )
        {
            if (effect == null)
                throw new ArgumentNullException("effect");

            ValidationHelper.VerifyPositionPair(startPosition, endPosition);            
            TextPointer   effectStart   = new TextPointer(startPosition);            

            // move to the first character symbol at or after Start position
            MoveToFirstCharacterSymbol(effectStart);

            TextEffect effectCopy;
            List<TextEffectTarget> list = new List<TextEffectTarget>();

            // we will now traverse the TOM and resolve text effects to the immediate parent 
            // of the characters. We are effectively applying the text effect onto 
            // block of continous text.
            while (effectStart.CompareTo(endPosition) < 0)
            {   
                // create a copy of the text effect 
                // so that we can set the CharacterIndex and Count
                effectCopy                 = effect.Clone();

                // create a position
                TextPointer continuousTextEnd = new TextPointer(effectStart);
                
                // move the position to the end of the continuous text block
                MoveToFirstNonCharacterSymbol(continuousTextEnd, endPosition);

                // make sure we are not out of the range
                continuousTextEnd = (TextPointer)TextPointerBase.Min(continuousTextEnd, endPosition);

                // set the character index to be the distance from the Start 
                // of this text block to the Start of the text container
                effectCopy.PositionStart = effectStart.TextContainer.Start.GetOffsetToPosition(effectStart);

                // count is the distance from the text block start to end
                effectCopy.PositionCount = effectStart.GetOffsetToPosition(continuousTextEnd);

                list.Add(
                    new TextEffectTarget(
                        effectStart.Parent, 
                        effectCopy
                        )
                 );
                
                // move the effectStart to the beginning of the next text block.
                effectStart = continuousTextEnd;
                MoveToFirstCharacterSymbol(effectStart);
            }

            return list.ToArray();
        }
예제 #2
0
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------

        //------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------

        //------------------------------------------------------
        //
        //  Protected Methods
        //
        //------------------------------------------------------

        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        #region Internal methods.

        /// <summary>
        /// Writes the container into the specified XmlWriter.
        /// </summary>
        internal void Write(TextPointer start, TextPointer end, XmlWriter writer)
        {
            System.Diagnostics.Debug.Assert(start != null);
            System.Diagnostics.Debug.Assert(end != null);
            System.Diagnostics.Debug.Assert(start.CompareTo(end) <= 0);
            System.Diagnostics.Debug.Assert(writer != null);

            WriteContainer(start, end, writer);
        }
예제 #3
0
 // move to the first non-character symbol, but not pass beyond the limit
 private static void MoveToFirstNonCharacterSymbol(
     TextPointer navigator,   // navigator to move
     TextPointer stopHint     // don't move further if we already pass beyond this point
     )
 {
     while (navigator.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text &&
            navigator.CompareTo(stopHint) < 0 &&
            navigator.MoveToNextContextPosition(LogicalDirection.Forward))
     {
         ;
     }
 }
예제 #4
0
        private static int GetCharOffsetToPosition(InlineCollection inlineCollection, TextPointer position, out TextPointer result)
        {
            int offset = 0;
            foreach (var inline in inlineCollection)
            {
                offset += GetCharOffsetToPosition(inline, position, out result);
                if (result == null || result.CompareTo(position) >= 0)
                    return offset;
            }

            result = null;
            return offset;
        }
예제 #5
0
        private static int GetCharOffsetToPosition(BlockCollection blockCollection, TextPointer position, out TextPointer result)
        {
            int offset = 0;
            foreach (var block in blockCollection)
            {
                offset += GetCharOffsetToPosition(block, position, out result);
                if (result == null || result.CompareTo(position) >= 0)
                    return offset;
            }

            result = null;
            return offset;
        }
예제 #6
0
        public static int GetCharOffsetToPosition(this FlowDocument document, TextPointer position)
        {
            if (document == null)
                throw new ArgumentNullException("document");
            if (position == null)
                throw new ArgumentNullException("position");

            if (position.CompareTo(document.ContentStart) == 0)
                return 0;

            TextPointer result;
            return GetCharOffsetToPosition(document.Blocks, position, out result);
        }
        internal override Rect[] GetCharacterRects(TextPointer startPointer, TextPointer endPointer)
        {
            if (!invalidatedCache && cachedStartP != null && startPointer.CompareTo(cachedStartP) == 0)
            {
                return cachedRects;
            }
            else
            {
                cachedRects = base.GetCharacterRects(startPointer, endPointer);
                cachedStartP = startPointer;
                invalidatedCache = false;
            }

            return cachedRects;
        }
        // Token: 0x06003E2C RID: 15916 RVA: 0x0011D638 File Offset: 0x0011B838
        internal static TextTreeDeleteContentUndoUnit CreateDeleteContentUndoUnit(TextContainer tree, TextPointer start, TextPointer end)
        {
            if (start.CompareTo(end) == 0)
            {
                return(null);
            }
            UndoManager orClearUndoManager = TextTreeUndo.GetOrClearUndoManager(tree);

            if (orClearUndoManager == null)
            {
                return(null);
            }
            TextTreeDeleteContentUndoUnit textTreeDeleteContentUndoUnit = new TextTreeDeleteContentUndoUnit(tree, start, end);

            orClearUndoManager.Add(textTreeDeleteContentUndoUnit);
            return(textTreeDeleteContentUndoUnit);
        }
예제 #9
0
        // 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;
        }
        /// <summary>Initializes a new instance of the <see cref="T:System.Windows.Documents.Hyperlink" /> class, taking two <see cref="T:System.Windows.Documents.TextPointer" /> objects that indicate the beginning and end of a selection of content to be contained by the new <see cref="T:System.Windows.Documents.Hyperlink" />.</summary>
        /// <param name="start">A <see cref="T:System.Windows.Documents.TextPointer" /> indicating the beginning of a selection of content to be contained by the new <see cref="T:System.Windows.Documents.Hyperlink" />.</param>
        /// <param name="end">A <see cref="T:System.Windows.Documents.TextPointer" /> indicating the end of a selection of content to be contained by the new <see cref="T:System.Windows.Documents.Hyperlink" />.</param>
        /// <exception cref="T:System.ArgumentNullException">
        ///         <paramref name="start" /> or <paramref name="end" /> is <see langword="null" />.</exception>
        /// <exception cref="T:System.ArgumentException">
        ///         <paramref name="start" /> and <paramref name="end" /> do not resolve to a range of content suitable for enclosure by a <see cref="T:System.Windows.Documents.Span" /> element; for example, if <paramref name="start" /> and <paramref name="end" /> indicate positions in different paragraphs.</exception>
        // Token: 0x0600301F RID: 12319 RVA: 0x000D8A18 File Offset: 0x000D6C18
        public Hyperlink(TextPointer start, TextPointer end) : base(start, end)
        {
            TextPointer textPointer = base.ContentStart.CreatePointer();
            TextPointer contentEnd  = base.ContentEnd;

            while (textPointer.CompareTo(contentEnd) < 0)
            {
                Hyperlink hyperlink = textPointer.GetAdjacentElement(LogicalDirection.Forward) as Hyperlink;
                if (hyperlink != null)
                {
                    hyperlink.Reposition(null, null);
                }
                else
                {
                    textPointer.MoveToNextContextPosition(LogicalDirection.Forward);
                }
            }
        }
예제 #11
0
        //-------------------------------------------------------------------
        //
        //  Internal Methods
        //
        //-------------------------------------------------------------------

        #region Internal Methods

        /// <summary>
        /// Returns the integer "index" of a specified ListItem that is an immediate child of
        /// this List. This index is defined to be a sequential counter of ListElementItems only
        /// (skipping other elements) among this List's immediate children.
        ///
        /// The list item index of the first child of type ListItem is specified by
        /// this.StartListIndex, which has a default value of 1.
        ///
        /// The index returned by this method is used in the formation of some ListItem
        /// markers such as "(b)" and "viii." (as opposed to others, like disks and wedges,
        /// which are not sequential-position-dependent).
        /// </summary>
        /// <param name="item">The item whose index is to be returned.</param>
        /// <returns>Returns the index of a specified ListItem.</returns>
        internal int GetListItemIndex(ListItem item)
        {
            // Check for valid arg
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (item.Parent != this)
            {
                throw new InvalidOperationException(SR.Get(SRID.ListElementItemNotAChildOfList));
            }

            // Count ListItem siblings (not other element types) back to first item.
            int         itemIndex = StartIndex;
            TextPointer textNav   = new TextPointer(this.ContentStart);

            while (textNav.CompareTo(this.ContentEnd) != 0)
            {
                // ListItem is a content element, so look for ElementStart runs only
                if (textNav.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart)
                {
                    DependencyObject element = textNav.GetAdjacentElementFromOuterPosition(LogicalDirection.Forward);
                    if (element is ListItem)
                    {
                        if (element == item)
                        {
                            break;
                        }
                        if (itemIndex < int.MaxValue)
                        {
                            ++itemIndex;
                        }
                    }
                    // Skip entire content element content, because we are looking
                    // only for immediate children.
                    textNav.MoveToPosition(((TextElement)element).ElementEnd);
                }
                else
                {
                    textNav.MoveToNextContextPosition(LogicalDirection.Forward);
                }
            }
            return(itemIndex);
        }
예제 #12
0
        // Checks whether two paragraphs are meargeable.
        // To be meargeable they need to be separated by s sequence of closing, then opening
        // tags only.
        // And all tags must be Sections/Lists/ListItems only.
        internal static bool ParagraphsAreMergeable(Block firstParagraphOrBlockUIContainer, Block secondParagraphOrBlockUIContainer)
        {
            if (firstParagraphOrBlockUIContainer == null || secondParagraphOrBlockUIContainer == null ||
                firstParagraphOrBlockUIContainer == secondParagraphOrBlockUIContainer)
            {
                return(false); // nothing to merge
            }

            TextPointer position = firstParagraphOrBlockUIContainer.ElementEnd;
            TextPointer startOfSecondParagraph = secondParagraphOrBlockUIContainer.ElementStart;

            // Skip and check all closing tags (if any)
            while (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd)
            {
                if (!TextSchema.AllowsParagraphMerging(position.Parent.GetType()))
                {
                    return(false); // Crossing hard-structured element. Paragraphs are not meargeable.
                }

                position = position.GetNextContextPosition(LogicalDirection.Forward);
            }

            // Skip and check all opening tags (if any)
            while (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart)
            {
                if (position.CompareTo(startOfSecondParagraph) == 0)
                {
                    // Successfully skipped all tags, and reached the seconfParagraph.
                    // The paragraphs are meargeable.
                    return(true);
                }

                position = position.GetNextContextPosition(LogicalDirection.Forward);

                if (!TextSchema.AllowsParagraphMerging(position.Parent.GetType()))
                {
                    return(false); // Crossing hardd-structured element. Paragraphs are not meargeable.
                }
            }

            // Non-tag run found. Paragraphs are not meargeable.
            return(false);
        }
예제 #13
0
        /// <summary>
        /// Creates a new Hyperlink instance covering existing content.
        /// </summary>
        /// <param name="start">
        /// Start position of the new Hyperlink.
        /// </param>
        /// <param name="end">
        /// End position of the new Hyperlink.
        /// </param>
        /// <remarks>
        /// start and end must both be parented by the same Paragraph, otherwise
        /// the method will raise an ArgumentException.
        /// </remarks>
        public Hyperlink(TextPointer start, TextPointer end) : base(start, end)
        {
            // After inserting this Hyperlink, we need to extract any child Hyperlinks.

            TextPointer navigator = this.ContentStart.CreatePointer();
            TextPointer stop      = this.ContentEnd;

            while (navigator.CompareTo(stop) < 0)
            {
                Hyperlink hyperlink = navigator.GetAdjacentElement(LogicalDirection.Forward) as Hyperlink;

                if (hyperlink != null)
                {
                    hyperlink.Reposition(null, null);
                }
                else
                {
                    navigator.MoveToNextContextPosition(LogicalDirection.Forward);
                }
            }
        }
예제 #14
0
        // 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);
        }
예제 #15
0
        // Token: 0x060031B9 RID: 12729 RVA: 0x000DBB64 File Offset: 0x000D9D64
        internal int GetListItemIndex(ListItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (item.Parent != this)
            {
                throw new InvalidOperationException(SR.Get("ListElementItemNotAChildOfList"));
            }
            int         num         = this.StartIndex;
            TextPointer textPointer = new TextPointer(base.ContentStart);

            while (textPointer.CompareTo(base.ContentEnd) != 0)
            {
                if (textPointer.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart)
                {
                    DependencyObject adjacentElementFromOuterPosition = textPointer.GetAdjacentElementFromOuterPosition(LogicalDirection.Forward);
                    if (adjacentElementFromOuterPosition is ListItem)
                    {
                        if (adjacentElementFromOuterPosition == item)
                        {
                            break;
                        }
                        if (num < 2147483647)
                        {
                            num++;
                        }
                    }
                    textPointer.MoveToPosition(((TextElement)adjacentElementFromOuterPosition).ElementEnd);
                }
                else
                {
                    textPointer.MoveToNextContextPosition(LogicalDirection.Forward);
                }
            }
            return(num);
        }
예제 #16
0
      /// <summary>
      /// Find the input string within the document, starting at the specified position.
      /// </summary>
      /// <param name="position">the current text position</param>
      /// <param name="input">input text</param>
      /// <returns>An <see cref="TextRange"/> representing the (next) matching string within the text container. Null if there are no matches.</returns>
      public TextRange FindNext(ref TextPointer position, String input)
      {
         FindText(input);

         foreach (var result in _searchHits)
         {
            if (position.CompareTo(result.End) < 0)
            {
               position = result.Start;
               double top = this.PointToScreen(position.GetLineStartPosition(0).GetCharacterRect(LogicalDirection.Forward).TopLeft).Y + this.PointFromScreen(new System.Windows.Point(0, 0)).Y;
               Trace.WriteLine(string.Format(" Top: {0}, CharOffset: {1}", top, position));
               ScrollViewer.ScrollToVerticalOffset(ScrollViewer.VerticalOffset + top);
               position = result.End;
               return result;
            }
         }
         return null;
      }
 // Token: 0x06003922 RID: 14626 RVA: 0x001031AC File Offset: 0x001013AC
 private static void MoveToFirstNonCharacterSymbol(TextPointer navigator, TextPointer stopHint)
 {
     while (navigator.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text && navigator.CompareTo(stopHint) < 0 && navigator.MoveToNextContextPosition(LogicalDirection.Forward))
     {
     }
 }
예제 #18
0
        // ....................................................................
        // 
        // Row editing 
        //
        // .................................................................... 

        #region Row Editing

        /// <summary> 
        /// Checks whether the given TextPointer is at row end position, where text insertion is impossible
        /// and returns a following position where text insertion or pasting is valid. 
        /// New paragraphs is creeated at the end of TextContainer if necessary. 
        /// </summary>
        internal static TextPointer EnsureInsertionPosition(TextPointer position) 
        {
            Invariant.Assert(position != null, "null check: position");

            // Normalize the pointer 
            position = position.GetInsertionPosition(position.LogicalDirection);
 
            if (!TextPointerBase.IsAtInsertionPosition(position)) 
            {
                // There is no insertion positions in the whole document at all. 
                // Generate minimally necessary content to ensure at least one insertion position.
                position = CreateInsertionPositionInIncompleteContent(position);
            }
            else 
            {
                // Check if position is at one of special structural boundary positions, where we can potentially have an 
                // insertion position and create one. 

                if (position.IsAtRowEnd) 
                {
                    // Find a next insertion position within the scope of the parent table.
                    Table currentTable = TextRangeEditTables.GetTableFromPosition(position);
                    position = GetAdjustedRowEndPosition(currentTable, position); 

                    if (position.CompareTo(currentTable.ElementEnd) == 0) 
                    { 
                        // The range is at the end of table which is the last block of text container OR
                        // next insertion position crossed table boundary. 
                        // In both cases, we want to insert a paragraph after table end and move our insertion position there.
                        position = CreateImplicitParagraph(currentTable.ElementEnd);
                    }
                } 
                Invariant.Assert(!position.IsAtRowEnd, "position is not expected to be at RowEnd anymore");
 
                // Note that this is not an else if, because our next insertion position (if it is within the same table), 
                // can fall into one of the following cases. We need to handle it.
                if (TextPointerBase.IsInBlockUIContainer(position)) 
                {
                    BlockUIContainer blockUIContainer = (BlockUIContainer)position.Parent;
                    bool insertBefore = position.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart;
                    position = insertBefore 
                        ? CreateImplicitParagraph(blockUIContainer.ElementStart)
                        : CreateImplicitParagraph(blockUIContainer.ElementEnd); 
 
                    // Clean potentialy incomplete content
                    if (blockUIContainer.IsEmpty) 
                    {
                        blockUIContainer.RepositionWithContent(null);
                    }
                } 
                else if (TextPointerBase.IsBeforeFirstTable(position) || TextPointerBase.IsAtPotentialParagraphPosition(position))
                { 
                    position = CreateImplicitParagraph(position); 
                }
                else if (TextPointerBase.IsAtPotentialRunPosition(position)) 
                {
                    position = CreateImplicitRun(position);
                }
            } 

            Invariant.Assert(TextSchema.IsInTextContent(position), "position must be in text content now"); 
            return position; 
        }
예제 #19
0
        /// <summary>
        /// Deletes all equi-scoped segments of content from start TextPointer 
        /// up to fragment root. Thus clears one half of a fragment. 
        /// The other half remains untouched.
        /// All elements whose boundaries are crossed by this range 
        /// remain in the tree (except for emptied formatting elements).
        /// </summary>
        /// <param name="start">
        /// A position from which content clearinng starts. 
        /// All content segments between this position and a fragment
        /// root will be deleted. 
        /// </param> 
        /// <param name="end">
        /// A position indicating the other boundary of a fragment. 
        /// This position is used for fragment root identification.
        /// </param>
        private static void DeleteEquiScopedContent(TextPointer start, TextPointer end)
        { 
            // Validate parameters
            Invariant.Assert(start != null, "null check: start"); 
            Invariant.Assert(end != null, "null check: end"); 

            if (start.CompareTo(end) == 0) 
            {
                return;
            }
 
            if (start.Parent == end.Parent)
            { 
                DeleteContentBetweenPositions(start, end); 
                return;
            } 

            // Identify directional parameters
            LogicalDirection direction;
            LogicalDirection oppositeDirection; 
            TextPointerContext enterScopeSymbol;
            TextPointerContext leaveScopeSymbol; 
            ElementEdge edgeBeforeElement; 
            ElementEdge edgeAfterElement;
            if (start.CompareTo(end) < 0) 
            {
                direction = LogicalDirection.Forward;
                oppositeDirection = LogicalDirection.Backward;
                enterScopeSymbol = TextPointerContext.ElementStart; 
                leaveScopeSymbol = TextPointerContext.ElementEnd;
                edgeBeforeElement = ElementEdge.BeforeStart; 
                edgeAfterElement = ElementEdge.AfterEnd; 
            }
            else 
            {
                direction = LogicalDirection.Backward;
                oppositeDirection = LogicalDirection.Forward;
                enterScopeSymbol = TextPointerContext.ElementEnd; 
                leaveScopeSymbol = TextPointerContext.ElementStart;
                edgeBeforeElement = ElementEdge.AfterEnd; 
                edgeAfterElement = ElementEdge.BeforeStart; 
            }
 
            // previousPosition will store a location where nondeleted content starts
            TextPointer previousPosition = new TextPointer(start);
            // nextPosition runs toward other end until level change -
            // so that we could delete all content from previousPosition 
            // to nextPosition at once.
            TextPointer nextPosition = new TextPointer(start); 
 
            // Run nextPosition forward until the very end of affected range
            while (nextPosition.CompareTo(end) != 0) 
            {
                Invariant.Assert(direction == LogicalDirection.Forward && nextPosition.CompareTo(end) < 0 || direction == LogicalDirection.Backward && nextPosition.CompareTo(end) > 0,
                    "Inappropriate position ordering");
                Invariant.Assert(previousPosition.Parent == nextPosition.Parent, "inconsistent position Parents: previous and next"); 

                TextPointerContext pointerContext = nextPosition.GetPointerContext(direction); 
 
                if (pointerContext == TextPointerContext.Text || pointerContext == TextPointerContext.EmbeddedElement)
                { 
                    // Add this run to a collection of equi-scoped content
                    nextPosition.MoveToNextContextPosition(direction);

                    // Check if we went too far and return a little to end if necessary 
                    if (direction == LogicalDirection.Forward && nextPosition.CompareTo(end) > 0 || direction == LogicalDirection.Backward && nextPosition.CompareTo(end) < 0)
                    { 
                        Invariant.Assert(nextPosition.Parent == end.Parent, "inconsistent poaition Parents: next and end"); 
                        nextPosition.MoveToPosition(end);
                        break; 
                    }
                }
                else if (pointerContext == enterScopeSymbol)
                { 
                    // Jump over the element and continue collecting equi-scoped content
                    nextPosition.MoveToNextContextPosition(direction); 
                    ((ITextPointer)nextPosition).MoveToElementEdge(edgeAfterElement); 

                    // If our range crosses the element then we stop before its opening tag 
                    if (direction == LogicalDirection.Forward && nextPosition.CompareTo(end) >= 0 || direction == LogicalDirection.Backward && nextPosition.CompareTo(end) <= 0)
                    {
                        nextPosition.MoveToNextContextPosition(oppositeDirection);
                        ((ITextPointer)nextPosition).MoveToElementEdge(edgeBeforeElement); 
                        break;
                    } 
                } 
                else if (pointerContext == leaveScopeSymbol)
                { 
                    // Delete preceding content and continue on outer level
                    DeleteContentBetweenPositions(previousPosition, nextPosition);
                    if (!ExtractEmptyFormattingElements(previousPosition))
                    { 
                        // Continue on outer level
                        Invariant.Assert(nextPosition.GetPointerContext(direction) == leaveScopeSymbol, "Unexpected context of nextPosition"); 
                        nextPosition.MoveToNextContextPosition(direction); 
                    }
 
                    previousPosition.MoveToPosition(nextPosition);
                }
                else
                { 
                    Invariant.Assert(false, "Not expecting None context here");
                    Invariant.Assert(pointerContext == TextPointerContext.None, "Unknown pointer context"); 
                    break; 
                }
            } 
            Invariant.Assert(previousPosition.Parent == nextPosition.Parent, "inconsistent Parents: previousPosition, nextPosition");

            DeleteContentBetweenPositions(previousPosition, nextPosition);
        } 
예제 #20
0
파일: Span.cs 프로젝트: beda2280/wpf-1
        /// <summary>
        /// Creates a new Span instance covering existing content.
        /// </summary>
        /// <param name="start">
        /// Start position of the new Span.
        /// </param>
        /// <param name="end">
        /// End position of the new Span.
        /// </param>
        /// <remarks>
        /// start and end must both be parented by the same Paragraph, otherwise
        /// the method will raise an ArgumentException.
        /// </remarks>
        public Span(TextPointer start, TextPointer end)
        {
            if (start == null)
            {
                throw new ArgumentNullException("start");
            }
            if (end == null)
            {
                throw new ArgumentNullException("start");
            }
            if (start.TextContainer != end.TextContainer)
            {
                throw new ArgumentException(SR.Get(SRID.InDifferentTextContainers, "start", "end"));
            }
            if (start.CompareTo(end) > 0)
            {
                throw new ArgumentException(SR.Get(SRID.BadTextPositionOrder, "start", "end"));
            }

            start.TextContainer.BeginChange();
            try
            {
                start = TextRangeEditTables.EnsureInsertionPosition(start);
                Invariant.Assert(start.Parent is Run);
                end = TextRangeEditTables.EnsureInsertionPosition(end);
                Invariant.Assert(end.Parent is Run);

                if (start.Paragraph != end.Paragraph)
                {
                    throw new ArgumentException(SR.Get(SRID.InDifferentParagraphs, "start", "end"));
                }

                // If start or end positions have a Hyperlink ancestor, we cannot split them.
                Inline nonMergeableAncestor;
                if ((nonMergeableAncestor = start.GetNonMergeableInlineAncestor()) != null)
                {
                    throw new InvalidOperationException(SR.Get(SRID.TextSchema_CannotSplitElement, nonMergeableAncestor.GetType().Name));
                }
                if ((nonMergeableAncestor = end.GetNonMergeableInlineAncestor()) != null)
                {
                    throw new InvalidOperationException(SR.Get(SRID.TextSchema_CannotSplitElement, nonMergeableAncestor.GetType().Name));
                }

                TextElement commonAncestor = TextElement.GetCommonAncestor((TextElement)start.Parent, (TextElement)end.Parent);

                while (start.Parent != commonAncestor)
                {
                    start = SplitElement(start);
                }
                while (end.Parent != commonAncestor)
                {
                    end = SplitElement(end);
                }

                if (start.Parent is Run)
                {
                    start = SplitElement(start);
                }
                if (end.Parent is Run)
                {
                    end = SplitElement(end);
                }

                Invariant.Assert(start.Parent == end.Parent);
                Invariant.Assert(TextSchema.IsValidChild(/*position*/ start, /*childType*/ typeof(Span)));

                this.Reposition(start, end);
            }
            finally
            {
                start.TextContainer.EndChange();
            }
        }
예제 #21
0
        internal static bool UnindentListItems(TextRange range)
        {
            // If listitems in this range cross a list boundary, we cannot unindent them.
            if (!IsRangeWithinSingleList(range))
            {
                return(false);
            }

            ListItem firstListItem = TextPointerBase.GetListItem(range.Start);
            ListItem lastListItem  = TextPointerBase.GetListItem((TextPointer)TextRangeEdit.GetAdjustedRangeEnd(range.Start, range.End));

            // At this point it is possible that lastListItem is a child of
            // firstListItem.
            //
            // This is due to a special case in IsRangeWithinSingleList
            // which allows the input TextRange to cross List boundaries only
            // in the case where the TextRange ends adjacent to an insertion
            // position at the same level as the start, e.g.:
            //
            //    - parent item
            //      - start item (range starts here)
            //          - child item (range ends here)
            //      <start item must not have any siblings>
            //
            // Here we check for that special case and ensure that
            // lastListItem is at the same level as firstListItem.

            TextElement parent = (TextElement)lastListItem.Parent;

            while (parent != firstListItem.Parent)
            {
                lastListItem = parent as ListItem;
                parent       = (TextElement)parent.Parent;
            }
            if (lastListItem == null)
            {
                // This can happen if the input is a fragment, a collection
                // of ListItems not parented by an outer List.
                return(false);
            }

            // Cut wrapping list before startListItem
            if (firstListItem.PreviousListItem != null)
            {
                TextRangeEdit.SplitElement(firstListItem.ElementStart);
            }

            // Cut wrapping list after endListItem
            if (lastListItem.NextListItem != null)
            {
                TextRangeEdit.SplitElement(lastListItem.ElementEnd);
            }

            // Remove List wrapper from selected items
            List unindentedList = (List)firstListItem.Parent;

            // Check whether we have outer ListItem
            ListItem outerListItem = unindentedList.Parent as ListItem;

            if (outerListItem != null)
            {
                // Selected items belong to a nested list.
                // So we need to pull them to the level of enclosing ListItem, i.e. cut this ListItem.
                // In this case we also need to include trailing list into the last of selected items

                // Remove a wrapping List from selected items
                unindentedList.Reposition(null, null);

                // Remember end position of outerListItem to pull any trailing list or other blocks into the last of selected listitems
                TextPointer outerListItemEnd = outerListItem.ContentEnd;

                if (outerListItem.ContentStart.CompareTo(firstListItem.ElementStart) == 0)
                {
                    // There is nothing before first list item; so outer list item would be empty - just delete it
                    outerListItem.Reposition(null, null);
                }
                else
                {
                    // Wrap all stuff preceding firstListItem in outerListItem
                    outerListItem.Reposition(outerListItem.ContentStart, firstListItem.ElementStart);
                }

                if (outerListItemEnd.CompareTo(lastListItem.ElementEnd) == 0)
                {
                    // There are no following siblings to pull into last selected item; do nothing.
                }
                else
                {
                    // Pull trailing items (following siblings to the selected ones) into the last selected item

                    // Remember a position to merge any trailing list after lastListItem
                    TextPointer mergePosition = lastListItem.ContentEnd;

                    // Reposition last selectd ListItem so that it includes trailing list (or other block) as its children
                    lastListItem.Reposition(lastListItem.ContentStart, outerListItemEnd);

                    // Merge any trailing list with a sublist outdented with our listitem
                    MergeLists(mergePosition);
                }
            }
            else
            {
                // Selected items are not in nested list.
                // We need to simply unwrap them and convert to paragraphs

                TextPointer start = unindentedList.ElementStart;
                TextPointer end   = unindentedList.ElementEnd;

                // Save the list's FlowDirection value, to apply later to its children.
                object listFlowDirectionValue = unindentedList.GetValue(Paragraph.FlowDirectionProperty);

                // Remove a wrapping List from selected items
                unindentedList.Reposition(null, null);

                // Remove ListItems from all selected items
                ListItem listItem = firstListItem;
                while (listItem != null)
                {
                    ListItem nextListItem = listItem.ElementEnd.GetAdjacentElement(LogicalDirection.Forward) as ListItem;

                    // If this is an empty <ListItem></ListItem>, insert an explicit paragraph in it before deleting the list item.
                    if (listItem.ContentStart.CompareTo(listItem.ContentEnd) == 0)
                    {
                        TextRangeEditTables.EnsureInsertionPosition(listItem.ContentStart);
                    }

                    listItem.Reposition(null, null);
                    listItem = listItem == lastListItem ? null : nextListItem;
                }

                // Apply FlowDirection of the list just deleted to all its children.
                TextRangeEdit.SetParagraphProperty(start, end, Paragraph.FlowDirectionProperty, listFlowDirectionValue);

                // Merge lists on boundaries
                MergeLists(start);
                MergeLists(end);
            }

            return(true);
        }
        // Token: 0x06003B85 RID: 15237 RVA: 0x0010F26C File Offset: 0x0010D46C
        internal static bool UnindentListItems(TextRange range)
        {
            if (!TextRangeEditLists.IsRangeWithinSingleList(range))
            {
                return(false);
            }
            ListItem listItem  = TextPointerBase.GetListItem(range.Start);
            ListItem listItem2 = TextPointerBase.GetListItem((TextPointer)TextRangeEdit.GetAdjustedRangeEnd(range.Start, range.End));

            for (TextElement textElement = (TextElement)listItem2.Parent; textElement != listItem.Parent; textElement = (TextElement)textElement.Parent)
            {
                listItem2 = (textElement as ListItem);
            }
            if (listItem2 == null)
            {
                return(false);
            }
            if (listItem.PreviousListItem != null)
            {
                TextRangeEdit.SplitElement(listItem.ElementStart);
            }
            if (listItem2.NextListItem != null)
            {
                TextRangeEdit.SplitElement(listItem2.ElementEnd);
            }
            List     list      = (List)listItem.Parent;
            ListItem listItem3 = list.Parent as ListItem;

            if (listItem3 != null)
            {
                list.Reposition(null, null);
                TextPointer contentEnd = listItem3.ContentEnd;
                if (listItem3.ContentStart.CompareTo(listItem.ElementStart) == 0)
                {
                    listItem3.Reposition(null, null);
                }
                else
                {
                    listItem3.Reposition(listItem3.ContentStart, listItem.ElementStart);
                }
                if (contentEnd.CompareTo(listItem2.ElementEnd) != 0)
                {
                    TextPointer contentEnd2 = listItem2.ContentEnd;
                    listItem2.Reposition(listItem2.ContentStart, contentEnd);
                    TextRangeEditLists.MergeLists(contentEnd2);
                }
            }
            else
            {
                TextPointer elementStart = list.ElementStart;
                TextPointer elementEnd   = list.ElementEnd;
                object      value        = list.GetValue(Block.FlowDirectionProperty);
                list.Reposition(null, null);
                ListItem listItem5;
                for (ListItem listItem4 = listItem; listItem4 != null; listItem4 = ((listItem4 == listItem2) ? null : listItem5))
                {
                    listItem5 = (listItem4.ElementEnd.GetAdjacentElement(LogicalDirection.Forward) as ListItem);
                    if (listItem4.ContentStart.CompareTo(listItem4.ContentEnd) == 0)
                    {
                        TextRangeEditTables.EnsureInsertionPosition(listItem4.ContentStart);
                    }
                    listItem4.Reposition(null, null);
                }
                TextRangeEdit.SetParagraphProperty(elementStart, elementEnd, Block.FlowDirectionProperty, value);
                TextRangeEditLists.MergeLists(elementStart);
                TextRangeEditLists.MergeLists(elementEnd);
            }
            return(true);
        }
예제 #23
0
        /// <summary> 
        /// Applies a property to a range between start and end positions.
        /// </summary> 
        /// <param name="start">
        /// TextPointer identifying start of affected range.
        /// </param>
        /// <param name="end"> 
        /// TextPointer identifying end of affected range.
        /// </param> 
        /// <param name="formattingProperty"> 
        /// A dependency property whose value is supposed to applied to a range.
        /// </param> 
        /// <param name="value">
        /// A value for a property to apply.
        /// </param>
        /// <param name="propertyValueAction"> 
        /// Specifies how to use the value - as absolute, as increment or a decrement.
        /// </param> 
        internal static void SetInlineProperty(TextPointer start, TextPointer end, DependencyProperty formattingProperty, object value, PropertyValueAction propertyValueAction) 
        {
            // Check for corner case when we have siple text run with all properties set as requested. 
            // This case is iportant optimization for Backspace-Type scenario, when Springload formatting applies for nothing for 50 properties
            if (start.CompareTo(end) >= 0 ||
                propertyValueAction == PropertyValueAction.SetValue &&
                start.Parent is Run && 
                start.Parent == end.Parent && TextSchema.ValuesAreEqual(start.Parent.GetValue(formattingProperty), value))
            { 
                return; 
            }
 
            // Remove unnecessary spans on range ends - to optimize resulting markup
            RemoveUnnecessarySpans(start);
            RemoveUnnecessarySpans(end);
 
            if (TextSchema.IsStructuralCharacterProperty(formattingProperty))
            { 
                SetStructuralInlineProperty(start, end, formattingProperty, value); 
            }
            else 
            {
                SetNonStructuralInlineProperty(start, end, formattingProperty, value, propertyValueAction);
            }
        } 
예제 #24
0
        // Helper that walks paragraphs between start and end positions, applying passed formattingProperty value on them.
        private static void ApplyStructuralInlinePropertyAcrossParagraphs(TextPointer start, TextPointer end, DependencyProperty formattingProperty, object value) 
        {
            // We assume to call this method only for paragraph crossing case
            Invariant.Assert(start.Paragraph != null);
            Invariant.Assert(start.Paragraph.ContentEnd.CompareTo(end) < 0); 

            // Apply to first Paragraph 
            SetStructuralInlineProperty(start, start.Paragraph.ContentEnd, formattingProperty, value); 
            start = start.Paragraph.ElementEnd;
 
            // Apply to last paragraph
            if (end.Paragraph != null)
            {
                SetStructuralInlineProperty(end.Paragraph.ContentStart, end, formattingProperty, value); 
                end = end.Paragraph.ElementStart;
            } 
 
            // Now, loop through paragraphs between start and end positions
            while (start != null && start.CompareTo(end) < 0) 
            {
                if (start.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart &&
                    start.Parent is Paragraph)
                { 
                    Paragraph paragraph = (Paragraph)start.Parent;
 
                    // Apply property to paragraph just found. 
                    SetStructuralInlineProperty(paragraph.ContentStart, paragraph.ContentEnd, formattingProperty, value);
 
                    // Jump to Paragraph end to skip Inline formatting tags.
                    start = paragraph.ElementEnd;
                }
 
                start = start.GetNextContextPosition(LogicalDirection.Forward);
            } 
        } 
예제 #25
0
        private static void ApplyStructuralInlinePropertyAcrossRun(TextPointer start, TextPointer end, Run run, DependencyProperty formattingProperty, object value)
        { 
            if (start.CompareTo(end) == 0)
            {
                // When the range is empty we should ignore the command, except
                // for the case of empty Run which can be encountered in empty paragraphs 
                if (run.IsEmpty)
                { 
                    run.SetValue(formattingProperty, value); 
                }
            } 
            else
            {
                // Split elements at start and end boundaries.
                start = SplitFormattingElements(start, /*keepEmptyFormatting:*/false, /*limitingAncestor*/run.Parent as TextElement); 
                end = SplitFormattingElements(end, /*keepEmptyFormatting:*/false, /*limitingAncestor*/run.Parent as TextElement);
 
                run = (Run)start.GetAdjacentElement(LogicalDirection.Forward); 
                run.SetValue(formattingProperty, value);
            } 

            // Clear property value from all ancestors of this Run.
            FixupStructuralPropertyEnvironment(run, formattingProperty);
        } 
예제 #26
0
        // Helper that walks Run and Span elements between start and end positions, 
        // clearing value of passed formattingProperty on them.
        // 
        private static void ClearPropertyValueFromSpansAndRuns(TextPointer start, TextPointer end, DependencyProperty formattingProperty)
        {
            // Normalize start position forward.
            start = start.GetPositionAtOffset(0, LogicalDirection.Forward); 

            // Move to next context position before entering loop below, 
            // since in the loop we look backward. 
            start = start.GetNextContextPosition(LogicalDirection.Forward);
 
            while (start != null && start.CompareTo(end) < 0)
            {
                if (start.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart &&
                    TextSchema.IsFormattingType(start.Parent.GetType())) // look for Run/Span elements 
                {
                    start.Parent.ClearValue(formattingProperty); 
 
                    // Remove unnecessary Spans around this position, delete empty formatting elements (if any)
                    // and merge with adjacent inlines if they have identical set of formatting properties. 
                    MergeFormattingInlines(start);
                }

                start = start.GetNextContextPosition(LogicalDirection.Forward); 
            }
        } 
예제 #27
0
        // Finds a Run element with ElementStart at or after the given pointer
        // Creates Runs at potential run positions if encounters some. 
        private static Run GetNextRun(TextPointer pointer, TextPointer limit) 
        {
            Run run = null; 

            while (pointer != null && pointer.CompareTo(limit) < 0)
            {
                if (pointer.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart && 
                    (run = pointer.GetAdjacentElement(LogicalDirection.Forward) as Run) != null)
                { 
                    break; 
                }
 
                if (TextPointerBase.IsAtPotentialRunPosition(pointer))
                {
                    pointer = TextRangeEditTables.EnsureInsertionPosition(pointer);
                    Invariant.Assert(pointer.Parent is Run); 
                    run = pointer.Parent as Run;
                    break; 
                } 

                // Advance the scanning pointer 
                pointer = pointer.GetNextContextPosition(LogicalDirection.Forward);
            }

            return run; 
        }
예제 #28
0
        /// <summary> 
        /// Helper for TextContainer.DeleteContent allowing arbitrary 
        /// order of positions and doinng nothing in case of empty range.
        /// Removes remaining empty formatting elements - if they not inside empty blocks. 
        /// </summary>
        /// <param name="one">
        /// One of content boundary positions. May precede or follow the TextPointer two.
        /// Must belong to the same scope as TextPointer two. 
        /// </param>
        /// <param name="two"> 
        /// Another content boundary position. May precede or follow the TextPointer one. 
        /// Must belong to the same scope as TextPointer one.
        /// </param> 
        /// <returns>
        /// true if surrounding formatting elements have beed deleted as a side effect.
        /// </returns>
        private static bool DeleteContentBetweenPositions(TextPointer one, TextPointer two) 
        {
            Invariant.Assert(one.Parent == two.Parent, "inconsistent Parents: one and two"); 
            if (one.CompareTo(two) < 0) 
            {
                one.TextContainer.DeleteContentInternal(one, two); 
            }
            else if (one.CompareTo(two) > 0)
            {
                two.TextContainer.DeleteContentInternal(two, one); 
            }
            Invariant.Assert(one.CompareTo(two) == 0, "Positions one and two must be equal now"); 
 
            return false;
        } 
예제 #29
0
         public static TextRange FindText(TextPointer findContainerStartPosition, TextPointer findContainerEndPosition, String input, FindFlags flags, CultureInfo cultureInfo)
         {
            TextRange textRange = null;
            if (findContainerStartPosition.CompareTo(findContainerEndPosition) < 0)
            {
               try
               {
                  if (findMethod == null)
                  {
                     findMethod = typeof(FrameworkElement).Assembly.GetType("System.Windows.Documents.TextFindEngine").
                            GetMethod("Find", BindingFlags.Static | BindingFlags.Public);
                  }

                  textRange = findMethod.Invoke(null,
                     new Object[] { findContainerStartPosition,
                                    findContainerEndPosition,
                                    input, 
                                    flags, 
                                    CultureInfo.CurrentCulture 
                     }) as TextRange;
               }
               catch (ApplicationException)
               {
                  textRange = null;
               }
            }

            return textRange;
         }
예제 #30
0
 /// <summary>Initializes a new instance of the <see cref="T:System.Windows.Documents.Span" /> class, taking two <see cref="T:System.Windows.Documents.TextPointer" /> objects that indicate the beginning and end of a selection of content that the new <see cref="T:System.Windows.Documents.Span" /> will contain.</summary>
 /// <param name="start">A <see cref="T:System.Windows.Documents.TextPointer" /> that indicates the beginning of a selection of content that the new <see cref="T:System.Windows.Documents.Span" /> will contain.</param>
 /// <param name="end">A <see cref="T:System.Windows.Documents.TextPointer" /> that indicates the end of a selection of content that the new <see cref="T:System.Windows.Documents.Span" /> will contain.</param>
 /// <exception cref="T:System.ArgumentNullException">Raised when <paramref name="start" /> or <paramref name="end" /> is null.</exception>
 /// <exception cref="T:System.ArgumentException">Raised when <paramref name="start" /> and <paramref name="end" /> do not resolve to a range of content suitable for enclosure by a <see cref="T:System.Windows.Documents.Span" /> element; for example, if <paramref name="start" /> and <paramref name="end" /> indicate positions in different paragraphs.</exception>
 // Token: 0x06003543 RID: 13635 RVA: 0x000F1218 File Offset: 0x000EF418
 public Span(TextPointer start, TextPointer end)
 {
     if (start == null)
     {
         throw new ArgumentNullException("start");
     }
     if (end == null)
     {
         throw new ArgumentNullException("start");
     }
     if (start.TextContainer != end.TextContainer)
     {
         throw new ArgumentException(SR.Get("InDifferentTextContainers", new object[]
         {
             "start",
             "end"
         }));
     }
     if (start.CompareTo(end) > 0)
     {
         throw new ArgumentException(SR.Get("BadTextPositionOrder", new object[]
         {
             "start",
             "end"
         }));
     }
     start.TextContainer.BeginChange();
     try
     {
         start = TextRangeEditTables.EnsureInsertionPosition(start);
         Invariant.Assert(start.Parent is Run);
         end = TextRangeEditTables.EnsureInsertionPosition(end);
         Invariant.Assert(end.Parent is Run);
         if (start.Paragraph != end.Paragraph)
         {
             throw new ArgumentException(SR.Get("InDifferentParagraphs", new object[]
             {
                 "start",
                 "end"
             }));
         }
         Inline nonMergeableInlineAncestor;
         if ((nonMergeableInlineAncestor = start.GetNonMergeableInlineAncestor()) != null)
         {
             throw new InvalidOperationException(SR.Get("TextSchema_CannotSplitElement", new object[]
             {
                 nonMergeableInlineAncestor.GetType().Name
             }));
         }
         if ((nonMergeableInlineAncestor = end.GetNonMergeableInlineAncestor()) != null)
         {
             throw new InvalidOperationException(SR.Get("TextSchema_CannotSplitElement", new object[]
             {
                 nonMergeableInlineAncestor.GetType().Name
             }));
         }
         TextElement commonAncestor = TextElement.GetCommonAncestor((TextElement)start.Parent, (TextElement)end.Parent);
         while (start.Parent != commonAncestor)
         {
             start = this.SplitElement(start);
         }
         while (end.Parent != commonAncestor)
         {
             end = this.SplitElement(end);
         }
         if (start.Parent is Run)
         {
             start = this.SplitElement(start);
         }
         if (end.Parent is Run)
         {
             end = this.SplitElement(end);
         }
         Invariant.Assert(start.Parent == end.Parent);
         Invariant.Assert(TextSchema.IsValidChild(start, typeof(Span)));
         base.Reposition(start, end);
     }
     finally
     {
         start.TextContainer.EndChange();
     }
 }
예제 #31
0
        /// <summary>
        /// Applies formatting properties for whole block elements. 
        /// </summary>
        /// <param name="start">
        /// a position within first block in sequence
        /// </param> 
        /// <param name="end">
        /// a positionn within last block in sequence 
        /// </param> 
        /// <param name="property">
        /// property changed on blocks 
        /// </param>
        /// <param name="value">
        /// value for the property
        /// </param> 
        /// <param name="propertyValueAction">
        /// Specifies how to use the value - as absolute, as increment or a decrement. 
        /// </param> 
        internal static void SetParagraphProperty(TextPointer start, TextPointer end, DependencyProperty property, object value, PropertyValueAction propertyValueAction)
        { 
            Invariant.Assert(start != null, "null check: start");
            Invariant.Assert(end != null, "null check: end");
            Invariant.Assert(start.CompareTo(end) <= 0, "expecting: start <= end");
            Invariant.Assert(property != null, "null check: property"); 

            // Exclude last opening tag to avoid affecting a paragraph following the selection 
            end = (TextPointer)TextRangeEdit.GetAdjustedRangeEnd(start, end); 

            // Expand start pointer to the beginning of the first paragraph/blockuicontainer 
            Block startParagraphOrBlockUIContainer = start.ParagraphOrBlockUIContainer;
            if (startParagraphOrBlockUIContainer != null)
            {
                start = startParagraphOrBlockUIContainer.ContentStart; 
            }
 
            // Applying FlowDirection requires splitting all containing lists on the range boundaries 
            // because the property is applied to whole List element (to affect bullet appearence)
            if (property == Block.FlowDirectionProperty) 
            {
                // Split any boundary lists if needed.
                // We want to maintain the invariant that all lists and paragraphs within a list, have the same FlowDirection value.
                // If paragraph FlowDirection command requests a different value of FlowDirection on parts of a list, 
                // we split the list to maintain this invariant.
                if (!TextRangeEditLists.SplitListsForFlowDirectionChange(start, end, value)) 
                { 
                    // If lists at start and end cannot be split successfully, we cannot apply FlowDirection property to the paragraph content.
                    return; 
                }

                // And expand range start to the beginning of the containing list
                ListItem listItem = start.GetListAncestor(); 
                if (listItem != null && listItem.List != null)
                { 
                    start = listItem.List.ElementStart; 
                }
            } 

            // Walk all paragraphs in the affected segment. For FlowDirection property, also walk lists.
            SetParagraphPropertyWorker(start, end, property, value, propertyValueAction);
        } 
예제 #32
0
        /// <summary>
        /// Makes sure that the content spanned by the range is totally deleted 
        /// including all structural elements and boundaries.
        /// We need this method to be able to make the range empty for any kind of content. 
        /// This operation is straightforward for all kinds of ranges expect for 
        /// TableCellRange. For cell range it means merging all selected cells
        /// and deleting the text content of resulting cell. 
        /// </summary>
        internal static void DeleteContent(TextPointer start, TextPointer end)
        {
            // Order positions, as we do not to distinguish between anchor/moving ends in this operation; 
            // but the following code depends on start<=end ordering
            if (start.CompareTo(end) > 0) 
            { 
                TextPointer whatWasEnd = end;
                end = start; 
                start = whatWasEnd;
            }

            // Check whether we cross table structure boundaries 
            TableCell startCell;
            TableCell endCell; 
            TableRow startRow; 
            TableRow endRow;
            TableRowGroup startRowGroup; 
            TableRowGroup endRowGroup;
            Table startTable;
            Table endTable;
 
            // We need to run a loop here because after boundary tables deletions
            // we may encounter following tables, so that start/end range will be 
            // again table-crossing. 
            while (
                start.CompareTo(end) < 0 
                &&
                IdentifyTableElements(
                    /*anchorPosition:*/start, /*movingPosition:*/end,
                    /*includeCellAtMovingPosition:*/false, 
                    out startCell, out endCell,
                    out startRow, out endRow, 
                    out startRowGroup, out endRowGroup, 
                    out startTable, out endTable))
            { 
                if (startTable == null && endTable == null || startTable == endTable)
                {
                    bool isTableCellRange;
                    List<TextSegment> textSegments = TextRangeEditTables.BuildTableRange( 
                        /*anchorPosition:*/start,
                        /*movingPosition:*/end, 
                        /*includeCellAtMovingPosition*/false, 
                        out isTableCellRange);
 
                    if (isTableCellRange && textSegments != null)
                    {
                        // It is cell selection. Create the content of all selected cells
                        for (int i = 0; i < textSegments.Count; i++) 
                        {
                            ClearTableCells(textSegments[i]); 
                        } 
                        // Collapse the range to bypass the folowing paragraph deletion
                        end = start; 
                    }
                    else
                    {
                        // Our range is within one table, so we need to delete 
                        // crossed row boundaries
 
                        // Find start row 
                        if (startCell != null)
                        { 
                            startRow = startCell.Row;
                        }
                        else if (startRow != null)
                        { 
                            // do nothing here. we already have a start row for deletion.
                        } 
                        else if (startRowGroup != null) 
                        {
                            startRow = startRowGroup.Rows[0]; 
                        }

                        // Find end row
                        if (endCell != null) 
                        {
                            endRow = startCell.Row; 
                        } 
                        else if (endRow != null)
                        { 
                            // do nothing here. we already have an end row for deletion.
                        }
                        else if (endRowGroup != null)
                        { 
                            endRow = endRowGroup.Rows[endRowGroup.Rows.Count - 1];
                        } 
 
                        Invariant.Assert(startRow != null && endRow != null, "startRow and endRow cannot be null, since our range is within one table");
                        TextRange rowsSegment = new TextRange(startRow.ContentStart, endRow.ContentEnd); 
                        TextRangeEditTables.DeleteRows(rowsSegment); // it will take care of rowspans
                    }
                }
                else 
                {
                    // Table boundary is crossed on one or both of edges. 
                    // So we must delete half(s) of crossed table(s) 

                    if (startRow != null) 
                    {
                        // Table boundary is crossed on start edge.
                        // So we need to delete all rows from start to the end of this table.
 
                        // Store position immediately after the first table
                        start = startRow.Table.ElementEnd; 
 
                        // Delete all rows from startRow to the very end of the table
                        TextRange rowsSegment = new TextRange(startRow.ContentStart, startRow.Table.ContentEnd); 
                        TextRangeEditTables.DeleteRows(rowsSegment); // it will take care of rowspans
                    }

                    if (endRow != null) 
                    {
                        // Table boundary is crossed on end egde. 
                        // So we need to delete all rows from start of the table to this endRow. 

                        // Store position immediately before the second table 
                        end = endRow.Table.ElementStart;

                        // Delete all rows from the beginning of the table to endRow
                        TextRange rowsSegment = new TextRange(endRow.Table.ContentStart, endRow.ContentEnd); 
                        TextRangeEditTables.DeleteRows(rowsSegment);
                    } 
                } 
            }
 
            // Now that we do not cross table structure, we can apply simple paragraph content deletion.
            // Delete remaining content between tables
            if (start.CompareTo(end) < 0)
            { 
                // Note that both start and end are not normalized here,
                // which is important, say, when the block between deleted tables 
                // was another Table or something - we want to delete the whole thing, whatever it is 
                // and normalizting start/end would cross its boundary.
                TextRangeEdit.DeleteParagraphContent(start, end); 
            }
        }
        // Validates that the sibling element at this position belong to expected itemType (Inline, Block, ListItem)
        private static void ValidateMergingPositions(Type itemType, TextPointer start, TextPointer end)
        {
            if (start.CompareTo(end) < 0)
            {
                // Verify inner part
                TextPointerContext forwardFromStart = start.GetPointerContext(LogicalDirection.Forward);
                TextPointerContext backwardFromEnd = end.GetPointerContext(LogicalDirection.Backward);
                Invariant.Assert(forwardFromStart == TextPointerContext.ElementStart, "Expecting first opening tag of pasted fragment");
                Invariant.Assert(backwardFromEnd == TextPointerContext.ElementEnd, "Expecting last closing tag of pasted fragment");
                Invariant.Assert(itemType.IsAssignableFrom(start.GetAdjacentElement(LogicalDirection.Forward).GetType()), "The first pasted fragment item is expected to be a " + itemType.Name);
                Invariant.Assert(itemType.IsAssignableFrom(end.GetAdjacentElement(LogicalDirection.Backward).GetType()), "The last pasted fragment item is expected to be a " + itemType.Name);

                // Veryfy outer part
                TextPointerContext backwardFromStart = start.GetPointerContext(LogicalDirection.Backward);
                TextPointerContext forwardFromEnd = end.GetPointerContext(LogicalDirection.Forward);
                Invariant.Assert(backwardFromStart == TextPointerContext.ElementStart || backwardFromStart == TextPointerContext.ElementEnd || backwardFromStart == TextPointerContext.None, "Bad context preceding a pasted fragment");
                Invariant.Assert(!(backwardFromStart == TextPointerContext.ElementEnd) || itemType.IsAssignableFrom(start.GetAdjacentElement(LogicalDirection.Backward).GetType()), "An element preceding a pasted fragment is expected to be a " + itemType.Name);
                Invariant.Assert(forwardFromEnd == TextPointerContext.ElementStart || forwardFromEnd == TextPointerContext.ElementEnd || forwardFromEnd == TextPointerContext.None, "Bad context following a pasted fragment");
                Invariant.Assert(!(forwardFromEnd == TextPointerContext.ElementStart) || itemType.IsAssignableFrom(end.GetAdjacentElement(LogicalDirection.Forward).GetType()), "An element following a pasted fragment is expected to be a " + itemType.Name);
            }
        }
예제 #34
0
        // ------------------------------------------------------------------
        // IContentHost Helpers
        // ------------------------------------------------------------------

        /// <summary>
        /// Searches for an element in the _complexContent.TextContainer. If the element is found, returns the
        /// position at which it is found. Otherwise returns null.
        /// </summary>
        /// <param name="e">
        /// Element to be found.
        /// </param>
        /// <remarks>
        /// We assume that this function is called from within text if the caller knows that _complexContent exists
        /// and contains a TextContainer. Hence we assert for this condition within the function
        /// </remarks>
        private TextPointer FindElementPosition(IInputElement e)
        {
            // Parameter validation
            Debug.Assert(e != null);

            // Validate that this function is only called when a TextContainer exists as complex content
            Debug.Assert(_complexContent.TextContainer is TextContainer);

            TextPointer position;

            // If e is a TextElement we can optimize by checking its TextContainer
            if (e is TextElement)
            {
                if ((e as TextElement).TextContainer == _complexContent.TextContainer)
                {
                    // Element found
                    position = new TextPointer((e as TextElement).ElementStart);
                    return position;
                }
            }

            // Else: search for e in the complex content
            position = new TextPointer((TextPointer)_complexContent.TextContainer.Start);
            while (position.CompareTo((TextPointer)_complexContent.TextContainer.End) < 0)
            {
                // Search each position in _complexContent.TextContainer for the element
                switch (position.GetPointerContext(LogicalDirection.Forward))
                {
                    case TextPointerContext.EmbeddedElement:
                        DependencyObject embeddedObject = position.GetAdjacentElement(LogicalDirection.Forward);
                        if (embeddedObject is ContentElement || embeddedObject is UIElement)
                        {
                            if (embeddedObject == e as ContentElement || embeddedObject == e as UIElement)
                            {
                                return position;
                            }
                        }
                        break;
                    default:
                          break;
                }
                position.MoveByOffset(+1);
            }

            // Reached end of complex content without finding the element
            return null;
        }
        // Applies one property to a range from start to end to simulate inheritance of this property from source conntext
        private static void ApplyContextualProperty(Type targetType, TextPointer start, TextPointer end, DependencyProperty property, object value)
        {
            if (TextSchema.ValuesAreEqual(start.Parent.GetValue(property), value))
            {
                return; // The property at insertion position is the same as it was in source context. Nothing to do.
            }
            
            // Advance start pointer to enter pasted fragment
            start = start.GetNextContextPosition(LogicalDirection.Forward);

            while (start != null && start.CompareTo(end) < 0)
            {
                TextPointerContext passedContext = start.GetPointerContext(LogicalDirection.Backward);
                if (passedContext == TextPointerContext.ElementStart)
                {
                    TextElement element = (TextElement)start.Parent;

                    // Check if this element affects the property in question
                    if (element.ReadLocalValue(property) != DependencyProperty.UnsetValue ||
                        !TextSchema.ValuesAreEqual(element.GetValue(property), element.Parent.GetValue(property)))
                    {
                        // The element affects this property, so we can skip it
                        start = element.ElementEnd;
                    }
                    else if (targetType.IsAssignableFrom(element.GetType()))
                    {
                        start = element.ElementEnd;

                        if (targetType == typeof(Block) && start.CompareTo(end) > 0)
                        {
                            // Contextual properties should not apply to the last paragraph
                            // when it is merged with the following content -
                            // to avoid affecting the folowing visible content formatting.
                            break;
                        }

                        // This is topmost-level inline element which inherits this property.
                        // Set the value explicitly
                        if (!TextSchema.ValuesAreEqual(value, element.GetValue(property)))
                        {
                            element.ClearValue(property);
                            if (!TextSchema.ValuesAreEqual(value, element.GetValue(property)))
                            {
                                element.SetValue(property, value);
                            }

                            TextRangeEdit.MergeFormattingInlines(element.ElementStart);
                        }
                    }
                    else
                    {
                        // Traverse down into a structured (non-innline) element
                        start = start.GetNextContextPosition(LogicalDirection.Forward);
                    }
                }
                else
                {
                    // Traverse up from any element
                    Invariant.Assert(passedContext != TextPointerContext.None, "TextPointerContext.None is not expected");
                    start = start.GetNextContextPosition(LogicalDirection.Forward);
                }
            }
        }
        /// <summary>
        /// Find the corresponding <see cref="TextRange"/> instance 
        /// representing the input string given a specified text pointer position.
        /// </summary>
        /// <param name="position">the current text position</param>
        /// <param name="textToFind">input text</param>
        /// <param name="findOptions">the search option</param>
        /// <returns>An <see cref="TextRange"/> instance represeneting the matching string withing the text container.</returns>
        public TextRange GetTextRangeFromPosition(ref TextPointer position, String input, FindOptions findOptions)
        {
            Boolean matchCase = findOptions.MatchCase;
            Boolean matchWholeWord = findOptions.MatchWholeWord;

            TextRange textRange = null;

            while (position != null)
            {
                if (position.CompareTo(inputDocument.ContentEnd) == 0) //到了文档结尾
                {
                    break;
                }
                //是文本元素
                if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
                {
                    String textRun = position.GetTextInRun(LogicalDirection.Forward);  //读取文本
                    StringComparison stringComparison = matchCase ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase;
                  //进行查找
                    Int32 indexInRun = textRun.IndexOf(input, stringComparison);

                    if (indexInRun >= 0)  //找到了
                    {
                        position = position.GetPositionAtOffset(indexInRun);  //移动文字指针到开头
                        TextPointer nextPointer = position.GetPositionAtOffset(input.Length); //设定匹配项尾文字指针
                        textRange = new TextRange(position, nextPointer);

                        if (matchWholeWord) //是全字匹配的话
                        {
                            if (IsWholeWord(textRange)) // 测试匹配项是否是一个单词
                            {
                                // 是一个完整的单词
                                break;
                            }
                            else
                            {
                                // 找到的不是一个完整的单词,继续在本Run元素中查找
                                position = position.GetPositionAtOffset(input.Length);
                                return GetTextRangeFromPosition(ref position, input, findOptions);
                            }
                        }
                        else
                        {
                            //不要求全字匹配
                            position = position.GetPositionAtOffset(input.Length);
                            break;
                        }
                    }
                    else
                    {
                        // 没找到匹配项,移到当前的Run元素之后 "textRun".
                        position = position.GetPositionAtOffset(textRun.Length);
                    }
                }
                else
                {
                    //如果当前位置不是文本类型的元素,继续"前进",跳过这些非文本元素.
                    position = position.GetNextContextPosition(LogicalDirection.Forward);
                }
            }

            return textRange;
        }
예제 #37
0
        // Finds a Paragraph/BlockUIContainer/List element with ElementStart before or at the given pointer 
        // Creates implicit paragraphs at potential paragraph positions if needed 
        private static Block GetNextBlock(TextPointer pointer, TextPointer limit)
        { 
            Block block = null;

            while (pointer != null && pointer.CompareTo(limit) <= 0)
            { 
                if (pointer.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart)
                { 
                    block = pointer.Parent as Block; 
                    if (block is Paragraph || block is BlockUIContainer || block is List)
                    { 
                        break;
                    }
                }
 
                if (TextPointerBase.IsAtPotentialParagraphPosition(pointer))
                { 
                    pointer = TextRangeEditTables.EnsureInsertionPosition(pointer); 
                    block = pointer.Paragraph;
                    Invariant.Assert(block != null); 
                    break;
                }

                // Advance the scanning pointer 
                pointer = pointer.GetNextContextPosition(LogicalDirection.Forward);
            } 
 
            return block;
        } 
        // Applies a whole property bag to a range from start to end to simulate inheritance of this property from source conntext
        private static void ApplyContextualProperties(TextPointer start, TextPointer end, TextElement propertyBag)
        {
            Invariant.Assert(propertyBag.IsEmpty && propertyBag.Parent == null, "propertyBag is supposed to be an empty element outside any tree");

            LocalValueEnumerator contextualProperties = propertyBag.GetLocalValueEnumerator();

            while (start.CompareTo(end) < 0 && contextualProperties.MoveNext())
            {
                // Note: we repeatedly check for IsEmpty because the selection
                // may become empty as a result of normalization after formatting
                // (thai character sequence).
                LocalValueEntry propertyEntry = contextualProperties.Current;
                DependencyProperty property = propertyEntry.Property;
                if (TextSchema.IsCharacterProperty(property) &&
                    TextSchema.IsParagraphProperty(property))
                {
                    // In case a property is both an Inline and Paragraph property,
                    // propertyBag element type (section or span) decides how it should be applied.
                    if (TextSchema.IsBlock(propertyBag.GetType()))
                    {
                        ApplyContextualProperty(typeof(Block), start, end, property, propertyEntry.Value);
                    }
                    else
                    {
                        ApplyContextualProperty(typeof(Inline), start, end, property, propertyEntry.Value);
                    }
                }
                else if (TextSchema.IsCharacterProperty(property))
                {
                    ApplyContextualProperty(typeof(Inline), start, end, property, propertyEntry.Value);
                }
                else if (TextSchema.IsParagraphProperty(property))
                {
                    ApplyContextualProperty(typeof(Block), start, end, property, propertyEntry.Value);
                }
            }

            // Merge formatting elements at end position
            TextRangeEdit.MergeFormattingInlines(start);
            TextRangeEdit.MergeFormattingInlines(end);
        }
예제 #39
0
        /// <summary>
        /// Creates a new Span instance covering existing content.
        /// </summary>
        /// <param name="start">
        /// Start position of the new Span.
        /// </param>
        /// <param name="end">
        /// End position of the new Span.
        /// </param>
        /// <remarks>
        /// start and end must both be parented by the same Paragraph, otherwise
        /// the method will raise an ArgumentException.
        /// </remarks>
        public Span(TextPointer start, TextPointer end)
        {
            if (start == null)
            {
                throw new ArgumentNullException("start");
            }
            if (end == null)
            {
                throw new ArgumentNullException("start");
            }
            if (start.TextContainer != end.TextContainer)
            {
                throw new ArgumentException(SR.Get(SRID.InDifferentTextContainers, "start", "end"));
            }
            if (start.CompareTo(end) > 0)
            {
                throw new ArgumentException(SR.Get(SRID.BadTextPositionOrder, "start", "end"));
            }

            start.TextContainer.BeginChange();
            try
            {
                start = TextRangeEditTables.EnsureInsertionPosition(start);
                Invariant.Assert(start.Parent is Run);
                end = TextRangeEditTables.EnsureInsertionPosition(end);
                Invariant.Assert(end.Parent is Run);

                if (start.Paragraph != end.Paragraph)
                {
                    throw new ArgumentException(SR.Get(SRID.InDifferentParagraphs, "start", "end"));
                }

                // If start or end positions have a Hyperlink ancestor, we cannot split them.
                Inline nonMergeableAncestor;
                if ((nonMergeableAncestor = start.GetNonMergeableInlineAncestor()) != null)
                {
                    throw new InvalidOperationException(SR.Get(SRID.TextSchema_CannotSplitElement, nonMergeableAncestor.GetType().Name));
                }
                if ((nonMergeableAncestor = end.GetNonMergeableInlineAncestor()) != null)
                {
                    throw new InvalidOperationException(SR.Get(SRID.TextSchema_CannotSplitElement, nonMergeableAncestor.GetType().Name));
                }

                TextElement commonAncestor = TextElement.GetCommonAncestor((TextElement)start.Parent, (TextElement)end.Parent);

                while (start.Parent != commonAncestor)
                {
                    start = SplitElement(start);
                }
                while (end.Parent != commonAncestor)
                {
                    end = SplitElement(end);
                }

                if (start.Parent is Run)
                {
                    start = SplitElement(start);
                }
                if (end.Parent is Run)
                {
                    end = SplitElement(end);
                }

                Invariant.Assert(start.Parent == end.Parent);
                Invariant.Assert(TextSchema.IsValidChild(/*position*/start, /*childType*/typeof(Span)));

                this.Reposition(start, end);
            }
            finally
            {
                start.TextContainer.EndChange();
            }
        }
        /// <summary>
        /// 根据搜索选项在文档中查找并替换全部匹配字串
        /// </summary>
        /// <param name="input">要查找的字串</param>
        /// <param name="replacement">用于替换的字串</param>
        /// <param name="findOptions">搜索选项 </param>
        /// <returns>进行了替换的次数</returns>
        /// <remarks>
        /// 此方法将移动文字指针到最后位置
        /// </remarks>
        public int ReplaceAll(String input, String replacement, FindOptions findOptions)
        {
            int count = 0;
            currentPosition = inputDocument.ContentStart;
            while (currentPosition.CompareTo(inputDocument.ContentEnd) < 0)
            {
                TextRange textRange = Replace(input, replacement, findOptions);
                if (textRange != null)
                {
                    count++;
                }
            }

            return count;
        }
예제 #41
0
        /// <summary>
        /// UpdateAccessKey - Scans forward in the tree looking for the access key marker, replacing it with access key element. We only support one find.
        /// </summary>
        private void UpdateAccessKey()
        {
            TextPointer navigator = new TextPointer(TextContainer.Start);

            while (!_accessKeyLocated && navigator.CompareTo(TextContainer.End) < 0 )
            {
                TextPointerContext symbolType = navigator.GetPointerContext(LogicalDirection.Forward);
                switch (symbolType)
                {
                    case TextPointerContext.Text:
                        string text = navigator.GetTextInRun(LogicalDirection.Forward);
                        int index = FindAccessKeyMarker(text);
                        if(index != -1 && index < text.Length - 1)
                        {
                            string keyText = StringInfo.GetNextTextElement(text, index + 1);
                            TextPointer keyEnd = navigator.GetPositionAtOffset(index + 1 + keyText.Length);

                            _accessKey = new Run(keyText);
                            _accessKey.Style = AccessKeyStyle;

                            RegisterAccessKey();

                            HasCustomSerializationStorage.SetValue(_accessKey, true);
                            _accessKeyLocated = true;

                            UninitializeTextContainerListener();

                            TextContainer.BeginChange();
                            try
                            {
                                TextPointer underlineStart = new TextPointer(navigator, index);
                                TextRangeEdit.DeleteInlineContent(underlineStart, keyEnd);
                                _accessKey.RepositionWithContent(underlineStart);

                            }
                            finally
                            {
                                TextContainer.EndChange();
                                InitializeTextContainerListener();
                            }
                        }

                        break;
                }
                navigator.MoveToNextContextPosition(LogicalDirection.Forward);
            }

            // Convert double _ to single _
            navigator = new TextPointer(TextContainer.Start);
            string accessKeyMarker = AccessKeyMarker.ToString();
            string doubleAccessKeyMarker = accessKeyMarker + accessKeyMarker;
            while (navigator.CompareTo(TextContainer.End) < 0)
            {
                TextPointerContext symbolType = navigator.GetPointerContext(LogicalDirection.Forward);
                switch (symbolType)
                {
                    case TextPointerContext.Text:
                        string text = navigator.GetTextInRun(LogicalDirection.Forward);
                        string nexText = text.Replace(doubleAccessKeyMarker, accessKeyMarker);
                        if (text != nexText)
                        {
                            TextPointer keyStart = new TextPointer(navigator, 0);
                            TextPointer keyEnd = new TextPointer(navigator, text.Length);

                            UninitializeTextContainerListener();
                            TextContainer.BeginChange();
                            try
                            {
                                keyEnd.InsertTextInRun(nexText);
                                TextRangeEdit.DeleteInlineContent(keyStart, keyEnd);
                            }
                            finally
                            {
                                TextContainer.EndChange();
                                InitializeTextContainerListener();
                            }
                        }

                        break;
                }
                navigator.MoveToNextContextPosition(LogicalDirection.Forward);
            }
        }
예제 #42
0
        // Removes inline properties that affect formatting from the given range 
        internal static void CharacterResetFormatting(TextPointer start, TextPointer end)
        { 
            if (start.CompareTo(end) < 0)
            {
                // Split formatting elements at range boundaries
                start = SplitFormattingElements(start, /*keepEmptyFormatting:*/false, /*preserveStructuralFormatting*/true, /*limitingAncestor*/null); 
                end = SplitFormattingElements(end, /*keepEmptyFormatting:*/false, /*preserveStructuralFormatting*/true, /*limitingAncestor*/null);
 
                while (start.CompareTo(end) < 0) 
                {
                    if (start.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart) 
                    {
                        // When entering a next element check whether we should clear its inline properties.
                        TextElement parent = (TextElement)start.Parent;
 
                        // Note we do cleaning for Inline elements only - so properties set on Paragraphs
                        // and other blocks will stay unchanged even if they set as local value. 
 
                        if (parent is Span && parent.ContentEnd.CompareTo(end) > 0)
                        { 
                            // Preserve Hyperlink/Span properties when it is partially selected
                        }
                        // We can't assume that custom types derived from Span, once their formatting
                        // properties are removed, can be transformed into a Span.  So treat custom 
                        // types as inlines, even if they're derived from Span.
                        else if (parent is Span && TextSchema.IsKnownType(parent.GetType())) 
                        { 
                            // Remember a position to merge inlines
                            TextPointer mergePosition = parent.ElementStart; 

                            // Preserve only non-formatting properties of original span element.
                            Span newSpan = TransferNonFormattingInlineProperties((Span)parent);
                            if (newSpan != null) 
                            {
                                newSpan.Reposition(parent.ElementStart, parent.ElementEnd); 
                                mergePosition = newSpan.ElementStart; 
                            }
 
                            // Throw away original span
                            parent.Reposition(null, null);

                            // Now that content has changed, we must try to merge inlines at this position 
                            MergeFormattingInlines(mergePosition);
                        } 
                        else if (parent is Inline) 
                        {
                            ClearFormattingInlineProperties((Inline)parent); 
                            // Now that properties may be removed we must try to merge this element with a preceding one
                            MergeFormattingInlines(parent.ElementStart);
                        }
                    } 
                    start = start.GetNextContextPosition(LogicalDirection.Forward);
                } 
 
                // At the end try ro merge elements at end position
                MergeFormattingInlines(end); 
            }
        }
예제 #43
0
        private static List<TextSegment> BuildCrossTableSelection( 
            TextPointer anchorPosition, TextPointer movingPosition, 
            TableRow anchorRow, TableRow movingRow)
        { 
            List<TextSegment> textSegments = new List<TextSegment>(1);
            if (anchorPosition.CompareTo(movingPosition) < 0)
            {
                textSegments.Add( 
                    NewNormalizedTextSegment(
                        anchorRow != null ? anchorRow.ContentStart : anchorPosition, 
                        movingRow != null ? movingRow.ContentEnd : movingPosition)); 
            }
            else 
            {
                textSegments.Add(
                    NewNormalizedTextSegment(
                        movingRow != null ? movingRow.ContentStart : movingPosition, 
                        anchorRow != null ? anchorRow.ContentEnd : anchorPosition));
            } 
 
            return textSegments;
        }