| File: MS\Internal\Annotations\Anchoring\TextViewSelectionProcessor.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // // // Description: // A SelectionProcessor subclass which produces locator parts that select // all anchors that intersect with the text in an element's TextView. // using System.Windows; using System.Globalization; using System.Windows.Annotations; using System.Windows.Documents; using System.Xml; namespace MS.Internal.Annotations.Anchoring { /// <summary> /// </summary> internal class TextViewSelectionProcessor : SelectionProcessor { //------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors /// <summary> /// Creates an instance of TextViewSelectionProcessor. /// </summary> public TextViewSelectionProcessor() { } #endregion Constructors //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Not implemented for this selection processor. /// </summary> /// <param name="selection1">selection to merge </param> /// <param name="selection2">other selection to merge </param> /// <param name="newSelection">always set to null because DocumentPageViews cannot be merged</param> /// <returns>always returns false because DocumentPageViewss cannot be merged</returns> public override bool MergeSelections(Object selection1, Object selection2, out Object newSelection) { newSelection = null; return false; } /// <summary> /// Simply returns the selection passed in which should be an element. /// </summary> /// <param name="selection">the selection to examine</param> /// <returns>a list containing the selection</returns> /// <exception cref="ArgumentNullException">selection is null</exception> /// <exception cref="ArgumentException">selection is of wrong type</exception> public override IList<DependencyObject> GetSelectedNodes(Object selection) { // Verify selection is a service provider that provides ITextView VerifySelection(selection); return new DependencyObject[] { (DependencyObject)selection }; } /// <summary> /// Simply returns the selection which should be an element. /// </summary> /// <param name="selection">the selection to examine</param> /// <returns>the selection itself</returns> /// <exception cref="ArgumentNullException">selection is null</exception> /// <exception cref="ArgumentException">selection is of wrong type</exception> public override UIElement GetParent(Object selection) { // Verify selection is a service provider that provides ITextView VerifySelection(selection); return (UIElement)selection; } /// <summary> /// Gets the anchor point for the selection. This isn't a runtime selection /// and therefore shouldn't be anchored to. This processor returns a point of /// (Double.NaN, Double.NaN). /// </summary> /// <param name="selection">the selection to examine</param> /// <exception cref="ArgumentNullException">selection is null</exception> /// <exception cref="ArgumentException">selection is of wrong type</exception> public override Point GetAnchorPoint(Object selection) { // Verify selection is a DocumentPageView VerifySelection(selection); // Returns the point (Nan,Nan) return new Point(double.NaN, double.NaN); } /// <summary> /// Creates one or more locator parts representing the portion /// of 'startNode' spanned by 'selection'. /// </summary> /// <param name="selection">the selection that is being processed</param> /// <param name="startNode">the node the locator parts should be in the /// context of</param> /// <returns>one or more locator parts representing the portion of 'startNode' spanned /// by 'selection'</returns> /// <exception cref="ArgumentNullException">startNode or selection is null</exception> /// <exception cref="ArgumentException">selection is of the wrong type</exception> public override IList<ContentLocatorPart> GenerateLocatorParts(Object selection, DependencyObject startNode) { ArgumentNullException.ThrowIfNull(startNode); List<ContentLocatorPart> res = null; ITextView textView = VerifySelection(selection); res = new List<ContentLocatorPart>(1); int startOffset; int endOffset; if (textView != null && textView.IsValid) { GetTextViewTextRange(textView, out startOffset, out endOffset); } else { // This causes no content to be loaded startOffset = -1; endOffset = -1; } ContentLocatorPart part = new ContentLocatorPart(TextSelectionProcessor.CharacterRangeElementName);// DocumentPageViewLocatorPart(); part.NameValuePairs.Add(TextSelectionProcessor.CountAttribute, 1.ToString(NumberFormatInfo.InvariantInfo)); part.NameValuePairs.Add(TextSelectionProcessor.SegmentAttribute + 0.ToString(NumberFormatInfo.InvariantInfo), startOffset.ToString(NumberFormatInfo.InvariantInfo) + TextSelectionProcessor.Separator + endOffset.ToString(NumberFormatInfo.InvariantInfo)); part.NameValuePairs.Add(TextSelectionProcessor.IncludeOverlaps, Boolean.TrueString); res.Add(part); return res; } /// <summary> /// This processor doesn't resolve ContentLocatorParts. It simply returns null. /// </summary> /// <param name="locatorPart">locator part specifying data to be spanned</param> /// <param name="startNode">the node to be spanned by the created /// selection</param> /// <param name="attachmentLevel">always set to AttachmentLevel.Unresolved</param> /// <returns>always returns null; this processor does not resolve ContentLocatorParts</returns> /// <exception cref="ArgumentNullException">locatorPart or startNode are null</exception> public override Object ResolveLocatorPart(ContentLocatorPart locatorPart, DependencyObject startNode, out AttachmentLevel attachmentLevel) { ArgumentNullException.ThrowIfNull(locatorPart); ArgumentNullException.ThrowIfNull(startNode); attachmentLevel = AttachmentLevel.Unresolved; // ContentLocator Parts generated by this selection processor cannot be resolved return null; } /// <summary> /// Returns a list of XmlQualifiedNames representing the /// the locator parts this processor can generate. This processor /// does not resolve these ContentLocatorParts - only generates them. /// </summary> public override XmlQualifiedName[] GetLocatorPartTypes() { return (XmlQualifiedName[])LocatorPartTypeNames.Clone(); } #endregion Public Methods //------------------------------------------------------ // // Public Operators // //------------------------------------------------------ //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ //------------------------------------------------------ // // Public Events // //------------------------------------------------------ //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// <summary> /// Returns the TextRange representing the visible contents of the ITextView. /// Also returns the same information in terms of the offsets to the start and end. /// </summary> /// <param name="textView">ITextView to get visible contents of</param> /// <param name="startOffset">offset into the document representing start of visible content</param> /// <param name="endOffset">offset into the document representing end of visible content</param> /// <returns>TextRange spanning all visible content</returns> internal static TextRange GetTextViewTextRange(ITextView textView, out int startOffset, out int endOffset) { Debug.Assert(textView != null); // These are the default in case we don't find any content in the DocumentPageView startOffset = int.MinValue; endOffset = 0; TextRange textRange = null; IList<TextSegment> segments = textView.TextSegments; if (segments != null && segments.Count > 0) { ITextPointer start = segments[0].Start; ITextPointer end = segments[segments.Count - 1].End; startOffset = end.TextContainer.Start.GetOffsetToPosition(start); endOffset = end.TextContainer.Start.GetOffsetToPosition(end); textRange = new TextRange(start, end); } return textRange; } #endregion Internal Methods //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods /// <summary> /// Verify the selection is of the correct type. /// </summary> /// <param name="selection">selection to verify</param> /// <returns>the selection cast to the necessary type</returns> private ITextView VerifySelection(object selection) { ArgumentNullException.ThrowIfNull(selection); IServiceProvider provider = selection as IServiceProvider; if (provider == null) throw new ArgumentException(SR.SelectionMustBeServiceProvider, nameof(selection)); ITextView textView = provider.GetService(typeof(ITextView)) as ITextView; return textView; } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ #region Private Fields // ContentLocator part types understood by this processor private static readonly XmlQualifiedName[] LocatorPartTypeNames = Array.Empty<XmlQualifiedName>(); #endregion Private Fields } }