// Deletes a specified run of content. // // On exit, // symbolsRemoved <== count of symbols actually removed. // removeStartIndex <== offset of first symbol affected by the edit. // // removeStartIndex is always <= endPosition.Offset, but it does not necessarily // match the position of the logically removed content. In some rare cases // a scoping element may be removed, meaning we have two or more runs of // removed content, and removeStartIndex + symbolsRemoved < the offset of // the last position affected by the operation. private void RemoveContent(ITextPointer startPosition, ITextPointer endPosition, out int symbolsRemoved, out int removeStartIndex) { symbolsRemoved = 0; removeStartIndex = startPosition.Offset; if (startPosition.CompareTo(endPosition) == 0) return; TextContainer container = (TextContainer)startPosition.TextContainer; symbolsRemoved = container.SymbolCount; if (startPosition is TextPointer) { _minSymbolsRemovedIndex = Int32.MaxValue; } startPosition.DeleteContentToPosition(endPosition); if (startPosition is TextPointer) { removeStartIndex = _minSymbolsRemovedIndex; } symbolsRemoved = symbolsRemoved - container.SymbolCount; }
/// <summary> /// Deletes a content covered by two positions assuming that /// the content crosses only paragraph-mergeable boundaries (if at all) - /// Paragraphs, Sections, Lists, ListItems, but not harder structural /// elements like Tables, TableCells, TableRows, Floaters, Figures. /// </summary> /// <param name="start"> /// Position indicating a beginning of deleted content. /// </param> /// <param name="end"> /// Position indicating an end of deleted content. /// </param> internal static void DeleteParagraphContent(ITextPointer start, ITextPointer end) { // Parameters validation Invariant.Assert(start != null, "null check: start"); Invariant.Assert(end != null, "null check: end"); Invariant.Assert(start.CompareTo(end) <= 0, "expecting: start <= end"); if (!(start is TextPointer)) { // Abstract text container. We can only use basic abstract functionality here: start.DeleteContentToPosition(end); return; } TextPointer startPosition = (TextPointer)start; TextPointer endPosition = (TextPointer)end; // Delete all equi-scoped content in the given range DeleteEquiScopedContent(startPosition, endPosition); // delete content runs from start to root DeleteEquiScopedContent(endPosition, startPosition); // delete contentruns from end to root // Merge crossed elements if (startPosition.CompareTo(endPosition) < 0) { if (TextPointerBase.IsAfterLastParagraph(endPosition)) { // This means that end position is after the last paragraph of a text container. // When the last paragraph is empty (and selection crosses its end boundary) // we need to delete it. // When last paragraph is not empty, we have to leave it as is. while (startPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart && startPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd) { // TextElement parent = (TextElement)startPosition.Parent; if (parent is Inline || TextSchema.AllowsParagraphMerging(parent.GetType())) { parent.RepositionWithContent(null); } else { break; } } } else { Block firstParagraphOrBlockUIContainer = startPosition.ParagraphOrBlockUIContainer; Block secondParagraphOrBlockUIContainer = endPosition.ParagraphOrBlockUIContainer; // If startPosition and/or endPosition is parented by an empty ListItem, create an implicit paragraph in it. // This will enable the following code to merge paragraphs in list items. if (firstParagraphOrBlockUIContainer == null && TextPointerBase.IsInEmptyListItem(startPosition)) { startPosition = TextRangeEditTables.EnsureInsertionPosition(startPosition); firstParagraphOrBlockUIContainer = startPosition.Paragraph; Invariant.Assert(firstParagraphOrBlockUIContainer != null, "EnsureInsertionPosition must create a paragraph inside list item - 1"); } if (secondParagraphOrBlockUIContainer == null && TextPointerBase.IsInEmptyListItem(endPosition)) { endPosition = TextRangeEditTables.EnsureInsertionPosition(endPosition); secondParagraphOrBlockUIContainer = endPosition.Paragraph; Invariant.Assert(secondParagraphOrBlockUIContainer != null, "EnsureInsertionPosition must create a paragraph inside list item - 2"); } if (firstParagraphOrBlockUIContainer != null && secondParagraphOrBlockUIContainer != null) { TextRangeEditLists.MergeParagraphs(firstParagraphOrBlockUIContainer, secondParagraphOrBlockUIContainer); } else { // When crossing BlockUIContainer boundaries we need to clear // any empty BlockUIContainers and empty adjacent paragraphs MergeEmptyParagraphsAndBlockUIContainers(startPosition, endPosition); } } } // Remove empty formatting elements MergeFormattingInlines(startPosition); MergeFormattingInlines(endPosition); // Check for remaining empty BlockUICOntainer or empty Hyperlink elements if (startPosition.Parent is BlockUIContainer && ((BlockUIContainer)startPosition.Parent).IsEmpty) { ((BlockUIContainer)startPosition.Parent).Reposition(null, null); } else if (startPosition.Parent is Hyperlink && ((Hyperlink)startPosition.Parent).IsEmpty) { ((Hyperlink)startPosition.Parent).Reposition(null, null); // After deleting an empty hyperlink, we might have inlines to merge. MergeFormattingInlines(startPosition); } // }