Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Annotations / Anchoring / TextSelectionProcessor.cs / 1305600 / TextSelectionProcessor.cs
//------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // TextSelectionProcessor uses TextAnchors to represent portions // of text that are anchors. It produces locator parts that // represent these TextAnchors and can generate TextAnchors from // the locator parts. // Spec: http://team/sites/ag/Specifications/Anchoring%20Namespace%20Spec.doc // // History: // 12/01/2002: magedz: Created - based on architectural discussions and design by axelk, rruiz, magedz // 04/01/2003: rruiz: Updated file as part of integrating into working system // 07/21/2003: rruiz: Ported to WCP tree. // 08/18/2003: rruiz: Updated to Anchoring Namespace Spec. // 03/29/2004: ssimova: Moved some common code toe TextSelectionHelper // //----------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Windows; using System.Windows.Annotations; using System.Windows.Annotations.Storage; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Documents; using System.Windows.Media; using System.Xml; using MS.Utility; using MS.Internal.Documents; namespace MS.Internal.Annotations.Anchoring { ////// TextSelectionProcessor uses TextAnchors to represent portions /// of text that are anchors. It produces locator parts that /// represent these TextAnchors and can generate TextAnchors from /// the locator parts. /// internal sealed class TextSelectionProcessor : SelectionProcessor { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Creates an instance of TextSelectionProcessor. /// public TextSelectionProcessor() { } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Merges the two anchors into one, if possible. /// /// anchor to merge /// other anchor to merge /// new anchor that contains the data from both /// anchor1 and anchor2 ///true if the anchors were merged, false otherwise /// ///anchor1 or anchor2 are /// null public override bool MergeSelections(Object anchor1, Object anchor2, out Object newAnchor) { return TextSelectionHelper.MergeSelections(anchor1, anchor2, out newAnchor); } ////// Gets the tree elements spanned by the selection. /// /// the selection to examine ///a list of elements spanned by the selection; never returns /// null ///selection is null ///selection is of wrong type public override IListGetSelectedNodes(Object selection) { return TextSelectionHelper.GetSelectedNodes(selection); } /// /// Gets the parent element of this selection. /// /// the selection to examine ///the parent element of the selection; can be null ///selection is null ///selection is of wrong type public override UIElement GetParent(Object selection) { return TextSelectionHelper.GetParent(selection); } ////// Gets the anchor point for the selection /// /// the selection to examine ///the anchor point of the selection; can be null ///selection is null ///selection is of wrong type public override Point GetAnchorPoint(Object selection) { return TextSelectionHelper.GetAnchorPoint(selection); } ////// Creates one or more locator parts representing the portion /// of 'startNode' spanned by 'selection'. /// /// the selection that is being processed /// the node the locator parts should be in the /// context of ///one or more locator parts representing the portion of 'startNode' spanned /// by 'selection' ///startNode or selection is null ///selection is of the wrong type public override IListGenerateLocatorParts(Object selection, DependencyObject startNode) { if (startNode == null) throw new ArgumentNullException("startNode"); if (selection == null) throw new ArgumentNullException("selection"); ITextPointer start; ITextPointer end; IList textSegments = null; TextSelectionHelper.CheckSelection(selection, out start, out end, out textSegments); if (!(start is TextPointer)) throw new ArgumentException(SR.Get(SRID.WrongSelectionType), "selection"); ITextPointer elementStart; ITextPointer elementEnd; // If we can't get the start/end of the node then we can't generate a locator part if (!GetNodesStartAndEnd(startNode, out elementStart, out elementEnd)) return null; if (elementStart.CompareTo(end) > 0) throw new ArgumentException(SR.Get(SRID.InvalidStartNodeForTextSelection), "startNode"); if (elementEnd.CompareTo(start) < 0) throw new ArgumentException(SR.Get(SRID.InvalidStartNodeForTextSelection), "startNode"); ContentLocatorPart part = new ContentLocatorPart(CharacterRangeElementName); int startOffset = 0; int endOffset = 0; for(int i = 0; i < textSegments.Count; i++) { GetTextSegmentValues(textSegments[i], elementStart, elementEnd, out startOffset, out endOffset); part.NameValuePairs.Add(SegmentAttribute + i.ToString(NumberFormatInfo.InvariantInfo), startOffset.ToString(NumberFormatInfo.InvariantInfo) + TextSelectionProcessor.Separator[0] + endOffset.ToString(NumberFormatInfo.InvariantInfo)); } part.NameValuePairs.Add(CountAttribute, textSegments.Count.ToString(NumberFormatInfo.InvariantInfo)); List res = new List (1); res.Add(part); return res; } /// /// Creates a selection object spanning the portion of 'startNode' /// specified by 'locatorPart'. /// /// locator part specifying data to be spanned /// the node to be spanned by the created /// selection /// set to AttachmentLevel.Full if the entire range of text /// was resolved, otherwise set to StartPortion, MiddlePortion, or EndPortion based on /// which part of the range was resolved ///a selection spanning the portion of 'startNode' specified by /// 'locatorPart', null if selection described by locator part could not be /// recreated ///locatorPart or startNode are /// null ///locatorPart is of the incorrect type public override Object ResolveLocatorPart(ContentLocatorPart locatorPart, DependencyObject startNode, out AttachmentLevel attachmentLevel) { if (startNode == null) throw new ArgumentNullException("startNode"); if (locatorPart == null) throw new ArgumentNullException("locatorPart"); if (CharacterRangeElementName != locatorPart.PartType) throw new ArgumentException(SR.Get(SRID.IncorrectLocatorPartType, locatorPart.PartType.Namespace + ":" + locatorPart.PartType.Name), "locatorPart"); // First we extract the offset and length of the // text range from the locator part. int startOffset = 0; int endOffset = 0; string stringCount = locatorPart.NameValuePairs[CountAttribute]; if (stringCount == null) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.CountAttribute)); int count = Int32.Parse(stringCount,NumberFormatInfo.InvariantInfo); TextAnchor anchor = new TextAnchor(); attachmentLevel = AttachmentLevel.Unresolved; for (int i = 0; i < count; i++) { GetLocatorPartSegmentValues(locatorPart, i, out startOffset, out endOffset); // Now we grab the TextRange so we can create a selection. // TextBox doesn't expose its internal TextRange so we use // its API for creating and getting the selection. ITextPointer elementStart; ITextPointer elementEnd; // If we can't get the start/end of the node then we can't resolve the locator part if (!GetNodesStartAndEnd(startNode, out elementStart, out elementEnd)) return null; // If the offset is not withing the element's text range we return null int textRangeLength = elementStart.GetOffsetToPosition(elementEnd); if (startOffset > textRangeLength) return null; ITextPointer start = elementStart.CreatePointer(startOffset);// new TextPointer((TextPointer)elementStart, startOffset); ITextPointer end = (textRangeLength <= endOffset) ? elementEnd.CreatePointer() : //new TextPointer((TextPointer)elementEnd) : elementStart.CreatePointer(endOffset);// new TextPointer((TextPointer)elementStart, endOffset); //we do not process 0 length selection if (start.CompareTo(end) >= 0) return null; anchor.AddTextSegment(start, end); } //we do not support 0 or negative length selection if (anchor.IsEmpty) { throw new ArgumentException(SR.Get(SRID.IncorrectAnchorLength), "locatorPart"); } attachmentLevel = AttachmentLevel.Full; if (_clamping) { ITextPointer currentStart = anchor.Start; ITextPointer currentEnd = anchor.End; IServiceProvider serviceProvider = null; ITextView textView = null; if (_targetPage != null) { serviceProvider = _targetPage as IServiceProvider; } else { FlowDocument content = currentStart.TextContainer.Parent as FlowDocument; serviceProvider = PathNode.GetParent(content as DependencyObject) as IServiceProvider; } Invariant.Assert(serviceProvider != null, "No ServiceProvider found to get TextView from."); textView = serviceProvider.GetService(typeof(ITextView)) as ITextView; Invariant.Assert(textView != null, "Null TextView provided by ServiceProvider."); anchor = TextAnchor.TrimToIntersectionWith(anchor, textView.TextSegments); if (anchor == null) { attachmentLevel = AttachmentLevel.Unresolved; } else { if (anchor.Start.CompareTo(currentStart) != 0) { attachmentLevel &= ~AttachmentLevel.StartPortion; } if (anchor.End.CompareTo(currentEnd) != 0) { attachmentLevel &= ~AttachmentLevel.EndPortion; } } } return anchor; } ////// Returns a list of XmlQualifiedNames representing the /// the locator parts this processor can resolve/generate. /// public override XmlQualifiedName[] GetLocatorPartTypes() { return (XmlQualifiedName[])LocatorPartTypeNames.Clone(); } #endregion Public Methods //------------------------------------------------------ // // Public Operators // //------------------------------------------------------ //----------------------------------------------------- // // Public Properties // //------------------------------------------------------ //----------------------------------------------------- // // Public Events // //----------------------------------------------------- //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties ////// Controls whether or not resolving should clamp the text /// anchors to the visible portion of a text container. Default /// value is true. /// internal bool Clamping { set { _clamping = value; } } #endregion Internal Properties //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// Gets the smallest offset and the largest offset from all the segments defined in the locator part. /// internal static void GetMaxMinLocatorPartValues(ContentLocatorPart locatorPart, out int startOffset, out int endOffset) { if (locatorPart == null) throw new ArgumentNullException("locatorPart"); string stringCount = locatorPart.NameValuePairs[CountAttribute]; if (stringCount == null) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.CountAttribute)); int count = Int32.Parse(stringCount,NumberFormatInfo.InvariantInfo); startOffset = Int32.MaxValue; endOffset = 0; int segStart; int segEnd; for (int i = 0; i < count; i++) { GetLocatorPartSegmentValues(locatorPart, i, out segStart, out segEnd); if (segStart < startOffset) startOffset = segStart; if (segEnd > endOffset) endOffset = segEnd; } } ////// Set the DocumentPageView this selection processor should use /// when clamping text anchors. If this target is not set then /// the set of DPVs held by the viewer are used. /// internal void SetTargetDocumentPageView(DocumentPageView target) { Debug.Assert(target != null); _targetPage = target; } #endregion Internal Methods //------------------------------------------------------ // // Internal Fields // //----------------------------------------------------- #region Internal Fields // Name of segment attribute internal const String SegmentAttribute = "Segment"; // Name of segment attribute internal const String CountAttribute = "Count"; // Name added to a LocatorPart with value "true" to mean // the LocatorPart matches for any overlapping LocatorPart internal const String IncludeOverlaps = "IncludeOverlaps"; // Potential separators for values in segment name/value pairs internal static readonly Char[] Separator = new Char[] { ',' }; // Name of locator part element internal static readonly XmlQualifiedName CharacterRangeElementName = new XmlQualifiedName("CharacterRange", AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); #endregion Internal Fields //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods ////// Extracts the values of attributes from a locator part. /// /// the locator part to extract values from /// the number of the segment to extract values for /// value of offset attribute /// value of length attribute private static void GetLocatorPartSegmentValues(ContentLocatorPart locatorPart, int segmentNumber, out int startOffset, out int endOffset) { if (segmentNumber < 0) throw new ArgumentException("segmentNumber"); string segmentString = locatorPart.NameValuePairs[SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo)]; string[] values = segmentString.Split(Separator); if (values.Length != 2) { throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo))); } startOffset = Int32.Parse(values[0], NumberFormatInfo.InvariantInfo); endOffset = Int32.Parse(values[1], NumberFormatInfo.InvariantInfo); } ////// Returns the TextContainer for a node that contains text. If the node /// doesn't have a TextContainer this method returns null. /// private ITextContainer GetTextContainer(DependencyObject startNode) { Debug.Assert(startNode != null); ITextContainer textContainer = null; IServiceProvider serviceProvider = startNode as IServiceProvider; if (serviceProvider != null) { textContainer = serviceProvider.GetService(typeof(ITextContainer)) as ITextContainer; } if (textContainer == null) { // Special case for TextBox which doesn't implement IServiceProvider TextBoxBase textBox = startNode as TextBoxBase; if (textBox != null) { textContainer = textBox.TextContainer; } } return textContainer; } ////// Returns ITextPointers positioned at the start and end of an element /// that contains text. /// private bool GetNodesStartAndEnd(DependencyObject startNode, out ITextPointer start, out ITextPointer end) { start = null; end = null; ITextContainer textContainer = GetTextContainer(startNode); if (textContainer != null) { start = textContainer.Start; end = textContainer.End; } else { // Special case for TextElement which doesn't expose its TextContainer TextElement textElement = startNode as TextElement; if (textElement != null) { start = textElement.ContentStart; end = textElement.ContentEnd; } else { return false; } } return true; } ////// Gets start and end offset for a text segment but clamps those values to the start and end /// of a given element. This way if a large text range is being resolved on a node that only contains /// a portion of the text range (such as a paragraph) the result only includes the content in that node. /// private void GetTextSegmentValues(TextSegment segment, ITextPointer elementStart, ITextPointer elementEnd, out int startOffset, out int endOffset) { startOffset = 0; endOffset = 0; if (elementStart.CompareTo(segment.Start) >= 0) { // segment starts before the start of the element startOffset = 0; } else { startOffset = elementStart.GetOffsetToPosition(segment.Start); } if (elementEnd.CompareTo(segment.End) >= 0) { endOffset = elementStart.GetOffsetToPosition(segment.End); } else { // segment ends after the end of the element endOffset = elementStart.GetOffsetToPosition(elementEnd); } } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- #region Private Fields // ContentLocatorPart types understood by this processor private static readonly XmlQualifiedName[] LocatorPartTypeNames = new XmlQualifiedName[] { CharacterRangeElementName }; // Optional DPV - used in printing case when there is no viewer available private DocumentPageView _targetPage = null; // Controls whether or not resolving clamps text anchors to // the visible portion of a TextContainer private bool _clamping = true; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // TextSelectionProcessor uses TextAnchors to represent portions // of text that are anchors. It produces locator parts that // represent these TextAnchors and can generate TextAnchors from // the locator parts. // Spec: http://team/sites/ag/Specifications/Anchoring%20Namespace%20Spec.doc // // History: // 12/01/2002: magedz: Created - based on architectural discussions and design by axelk, rruiz, magedz // 04/01/2003: rruiz: Updated file as part of integrating into working system // 07/21/2003: rruiz: Ported to WCP tree. // 08/18/2003: rruiz: Updated to Anchoring Namespace Spec. // 03/29/2004: ssimova: Moved some common code toe TextSelectionHelper // //----------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Windows; using System.Windows.Annotations; using System.Windows.Annotations.Storage; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Documents; using System.Windows.Media; using System.Xml; using MS.Utility; using MS.Internal.Documents; namespace MS.Internal.Annotations.Anchoring { ////// TextSelectionProcessor uses TextAnchors to represent portions /// of text that are anchors. It produces locator parts that /// represent these TextAnchors and can generate TextAnchors from /// the locator parts. /// internal sealed class TextSelectionProcessor : SelectionProcessor { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Creates an instance of TextSelectionProcessor. /// public TextSelectionProcessor() { } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Merges the two anchors into one, if possible. /// /// anchor to merge /// other anchor to merge /// new anchor that contains the data from both /// anchor1 and anchor2 ///true if the anchors were merged, false otherwise /// ///anchor1 or anchor2 are /// null public override bool MergeSelections(Object anchor1, Object anchor2, out Object newAnchor) { return TextSelectionHelper.MergeSelections(anchor1, anchor2, out newAnchor); } ////// Gets the tree elements spanned by the selection. /// /// the selection to examine ///a list of elements spanned by the selection; never returns /// null ///selection is null ///selection is of wrong type public override IListGetSelectedNodes(Object selection) { return TextSelectionHelper.GetSelectedNodes(selection); } /// /// Gets the parent element of this selection. /// /// the selection to examine ///the parent element of the selection; can be null ///selection is null ///selection is of wrong type public override UIElement GetParent(Object selection) { return TextSelectionHelper.GetParent(selection); } ////// Gets the anchor point for the selection /// /// the selection to examine ///the anchor point of the selection; can be null ///selection is null ///selection is of wrong type public override Point GetAnchorPoint(Object selection) { return TextSelectionHelper.GetAnchorPoint(selection); } ////// Creates one or more locator parts representing the portion /// of 'startNode' spanned by 'selection'. /// /// the selection that is being processed /// the node the locator parts should be in the /// context of ///one or more locator parts representing the portion of 'startNode' spanned /// by 'selection' ///startNode or selection is null ///selection is of the wrong type public override IListGenerateLocatorParts(Object selection, DependencyObject startNode) { if (startNode == null) throw new ArgumentNullException("startNode"); if (selection == null) throw new ArgumentNullException("selection"); ITextPointer start; ITextPointer end; IList textSegments = null; TextSelectionHelper.CheckSelection(selection, out start, out end, out textSegments); if (!(start is TextPointer)) throw new ArgumentException(SR.Get(SRID.WrongSelectionType), "selection"); ITextPointer elementStart; ITextPointer elementEnd; // If we can't get the start/end of the node then we can't generate a locator part if (!GetNodesStartAndEnd(startNode, out elementStart, out elementEnd)) return null; if (elementStart.CompareTo(end) > 0) throw new ArgumentException(SR.Get(SRID.InvalidStartNodeForTextSelection), "startNode"); if (elementEnd.CompareTo(start) < 0) throw new ArgumentException(SR.Get(SRID.InvalidStartNodeForTextSelection), "startNode"); ContentLocatorPart part = new ContentLocatorPart(CharacterRangeElementName); int startOffset = 0; int endOffset = 0; for(int i = 0; i < textSegments.Count; i++) { GetTextSegmentValues(textSegments[i], elementStart, elementEnd, out startOffset, out endOffset); part.NameValuePairs.Add(SegmentAttribute + i.ToString(NumberFormatInfo.InvariantInfo), startOffset.ToString(NumberFormatInfo.InvariantInfo) + TextSelectionProcessor.Separator[0] + endOffset.ToString(NumberFormatInfo.InvariantInfo)); } part.NameValuePairs.Add(CountAttribute, textSegments.Count.ToString(NumberFormatInfo.InvariantInfo)); List res = new List (1); res.Add(part); return res; } /// /// Creates a selection object spanning the portion of 'startNode' /// specified by 'locatorPart'. /// /// locator part specifying data to be spanned /// the node to be spanned by the created /// selection /// set to AttachmentLevel.Full if the entire range of text /// was resolved, otherwise set to StartPortion, MiddlePortion, or EndPortion based on /// which part of the range was resolved ///a selection spanning the portion of 'startNode' specified by /// 'locatorPart', null if selection described by locator part could not be /// recreated ///locatorPart or startNode are /// null ///locatorPart is of the incorrect type public override Object ResolveLocatorPart(ContentLocatorPart locatorPart, DependencyObject startNode, out AttachmentLevel attachmentLevel) { if (startNode == null) throw new ArgumentNullException("startNode"); if (locatorPart == null) throw new ArgumentNullException("locatorPart"); if (CharacterRangeElementName != locatorPart.PartType) throw new ArgumentException(SR.Get(SRID.IncorrectLocatorPartType, locatorPart.PartType.Namespace + ":" + locatorPart.PartType.Name), "locatorPart"); // First we extract the offset and length of the // text range from the locator part. int startOffset = 0; int endOffset = 0; string stringCount = locatorPart.NameValuePairs[CountAttribute]; if (stringCount == null) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.CountAttribute)); int count = Int32.Parse(stringCount,NumberFormatInfo.InvariantInfo); TextAnchor anchor = new TextAnchor(); attachmentLevel = AttachmentLevel.Unresolved; for (int i = 0; i < count; i++) { GetLocatorPartSegmentValues(locatorPart, i, out startOffset, out endOffset); // Now we grab the TextRange so we can create a selection. // TextBox doesn't expose its internal TextRange so we use // its API for creating and getting the selection. ITextPointer elementStart; ITextPointer elementEnd; // If we can't get the start/end of the node then we can't resolve the locator part if (!GetNodesStartAndEnd(startNode, out elementStart, out elementEnd)) return null; // If the offset is not withing the element's text range we return null int textRangeLength = elementStart.GetOffsetToPosition(elementEnd); if (startOffset > textRangeLength) return null; ITextPointer start = elementStart.CreatePointer(startOffset);// new TextPointer((TextPointer)elementStart, startOffset); ITextPointer end = (textRangeLength <= endOffset) ? elementEnd.CreatePointer() : //new TextPointer((TextPointer)elementEnd) : elementStart.CreatePointer(endOffset);// new TextPointer((TextPointer)elementStart, endOffset); //we do not process 0 length selection if (start.CompareTo(end) >= 0) return null; anchor.AddTextSegment(start, end); } //we do not support 0 or negative length selection if (anchor.IsEmpty) { throw new ArgumentException(SR.Get(SRID.IncorrectAnchorLength), "locatorPart"); } attachmentLevel = AttachmentLevel.Full; if (_clamping) { ITextPointer currentStart = anchor.Start; ITextPointer currentEnd = anchor.End; IServiceProvider serviceProvider = null; ITextView textView = null; if (_targetPage != null) { serviceProvider = _targetPage as IServiceProvider; } else { FlowDocument content = currentStart.TextContainer.Parent as FlowDocument; serviceProvider = PathNode.GetParent(content as DependencyObject) as IServiceProvider; } Invariant.Assert(serviceProvider != null, "No ServiceProvider found to get TextView from."); textView = serviceProvider.GetService(typeof(ITextView)) as ITextView; Invariant.Assert(textView != null, "Null TextView provided by ServiceProvider."); anchor = TextAnchor.TrimToIntersectionWith(anchor, textView.TextSegments); if (anchor == null) { attachmentLevel = AttachmentLevel.Unresolved; } else { if (anchor.Start.CompareTo(currentStart) != 0) { attachmentLevel &= ~AttachmentLevel.StartPortion; } if (anchor.End.CompareTo(currentEnd) != 0) { attachmentLevel &= ~AttachmentLevel.EndPortion; } } } return anchor; } ////// Returns a list of XmlQualifiedNames representing the /// the locator parts this processor can resolve/generate. /// public override XmlQualifiedName[] GetLocatorPartTypes() { return (XmlQualifiedName[])LocatorPartTypeNames.Clone(); } #endregion Public Methods //------------------------------------------------------ // // Public Operators // //------------------------------------------------------ //----------------------------------------------------- // // Public Properties // //------------------------------------------------------ //----------------------------------------------------- // // Public Events // //----------------------------------------------------- //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties ////// Controls whether or not resolving should clamp the text /// anchors to the visible portion of a text container. Default /// value is true. /// internal bool Clamping { set { _clamping = value; } } #endregion Internal Properties //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// Gets the smallest offset and the largest offset from all the segments defined in the locator part. /// internal static void GetMaxMinLocatorPartValues(ContentLocatorPart locatorPart, out int startOffset, out int endOffset) { if (locatorPart == null) throw new ArgumentNullException("locatorPart"); string stringCount = locatorPart.NameValuePairs[CountAttribute]; if (stringCount == null) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.CountAttribute)); int count = Int32.Parse(stringCount,NumberFormatInfo.InvariantInfo); startOffset = Int32.MaxValue; endOffset = 0; int segStart; int segEnd; for (int i = 0; i < count; i++) { GetLocatorPartSegmentValues(locatorPart, i, out segStart, out segEnd); if (segStart < startOffset) startOffset = segStart; if (segEnd > endOffset) endOffset = segEnd; } } ////// Set the DocumentPageView this selection processor should use /// when clamping text anchors. If this target is not set then /// the set of DPVs held by the viewer are used. /// internal void SetTargetDocumentPageView(DocumentPageView target) { Debug.Assert(target != null); _targetPage = target; } #endregion Internal Methods //------------------------------------------------------ // // Internal Fields // //----------------------------------------------------- #region Internal Fields // Name of segment attribute internal const String SegmentAttribute = "Segment"; // Name of segment attribute internal const String CountAttribute = "Count"; // Name added to a LocatorPart with value "true" to mean // the LocatorPart matches for any overlapping LocatorPart internal const String IncludeOverlaps = "IncludeOverlaps"; // Potential separators for values in segment name/value pairs internal static readonly Char[] Separator = new Char[] { ',' }; // Name of locator part element internal static readonly XmlQualifiedName CharacterRangeElementName = new XmlQualifiedName("CharacterRange", AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); #endregion Internal Fields //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods ////// Extracts the values of attributes from a locator part. /// /// the locator part to extract values from /// the number of the segment to extract values for /// value of offset attribute /// value of length attribute private static void GetLocatorPartSegmentValues(ContentLocatorPart locatorPart, int segmentNumber, out int startOffset, out int endOffset) { if (segmentNumber < 0) throw new ArgumentException("segmentNumber"); string segmentString = locatorPart.NameValuePairs[SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo)]; string[] values = segmentString.Split(Separator); if (values.Length != 2) { throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo))); } startOffset = Int32.Parse(values[0], NumberFormatInfo.InvariantInfo); endOffset = Int32.Parse(values[1], NumberFormatInfo.InvariantInfo); } ////// Returns the TextContainer for a node that contains text. If the node /// doesn't have a TextContainer this method returns null. /// private ITextContainer GetTextContainer(DependencyObject startNode) { Debug.Assert(startNode != null); ITextContainer textContainer = null; IServiceProvider serviceProvider = startNode as IServiceProvider; if (serviceProvider != null) { textContainer = serviceProvider.GetService(typeof(ITextContainer)) as ITextContainer; } if (textContainer == null) { // Special case for TextBox which doesn't implement IServiceProvider TextBoxBase textBox = startNode as TextBoxBase; if (textBox != null) { textContainer = textBox.TextContainer; } } return textContainer; } ////// Returns ITextPointers positioned at the start and end of an element /// that contains text. /// private bool GetNodesStartAndEnd(DependencyObject startNode, out ITextPointer start, out ITextPointer end) { start = null; end = null; ITextContainer textContainer = GetTextContainer(startNode); if (textContainer != null) { start = textContainer.Start; end = textContainer.End; } else { // Special case for TextElement which doesn't expose its TextContainer TextElement textElement = startNode as TextElement; if (textElement != null) { start = textElement.ContentStart; end = textElement.ContentEnd; } else { return false; } } return true; } ////// Gets start and end offset for a text segment but clamps those values to the start and end /// of a given element. This way if a large text range is being resolved on a node that only contains /// a portion of the text range (such as a paragraph) the result only includes the content in that node. /// private void GetTextSegmentValues(TextSegment segment, ITextPointer elementStart, ITextPointer elementEnd, out int startOffset, out int endOffset) { startOffset = 0; endOffset = 0; if (elementStart.CompareTo(segment.Start) >= 0) { // segment starts before the start of the element startOffset = 0; } else { startOffset = elementStart.GetOffsetToPosition(segment.Start); } if (elementEnd.CompareTo(segment.End) >= 0) { endOffset = elementStart.GetOffsetToPosition(segment.End); } else { // segment ends after the end of the element endOffset = elementStart.GetOffsetToPosition(elementEnd); } } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- #region Private Fields // ContentLocatorPart types understood by this processor private static readonly XmlQualifiedName[] LocatorPartTypeNames = new XmlQualifiedName[] { CharacterRangeElementName }; // Optional DPV - used in printing case when there is no viewer available private DocumentPageView _targetPage = null; // Controls whether or not resolving clamps text anchors to // the visible portion of a TextContainer private bool _clamping = true; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- NestPullup.cs
- BuildManagerHost.cs
- WpfKnownMemberInvoker.cs
- ADMembershipUser.cs
- ChildDocumentBlock.cs
- RtfNavigator.cs
- TypeName.cs
- ProxySimple.cs
- SqlTypeSystemProvider.cs
- RenderData.cs
- HttpListener.cs
- PassportAuthenticationModule.cs
- webclient.cs
- ListViewHitTestInfo.cs
- WCFServiceClientProxyGenerator.cs
- RelationshipSet.cs
- AuthStoreRoleProvider.cs
- SqlDataSourceCustomCommandEditor.cs
- SiteMapNodeItemEventArgs.cs
- CodeActivityContext.cs
- SqlColumnizer.cs
- CatalogZone.cs
- DefaultValueTypeConverter.cs
- HideDisabledControlAdapter.cs
- PnrpPeerResolver.cs
- SoundPlayerAction.cs
- QilTargetType.cs
- CopyNamespacesAction.cs
- SerializationObjectManager.cs
- ListenerHandler.cs
- XslTransformFileEditor.cs
- DatagridviewDisplayedBandsData.cs
- AddInServer.cs
- CfgParser.cs
- Main.cs
- ChangePassword.cs
- ProcessThreadCollection.cs
- RenderCapability.cs
- SiteMapHierarchicalDataSourceView.cs
- CodeTypeDeclaration.cs
- EntityContainerAssociationSet.cs
- UIElement.cs
- DbCommandDefinition.cs
- SqlCacheDependencySection.cs
- sqlmetadatafactory.cs
- XmlSchemaGroupRef.cs
- IpcPort.cs
- Wildcard.cs
- RawMouseInputReport.cs
- StatusBarPanelClickEvent.cs
- XmlUnspecifiedAttribute.cs
- WebHostedComPlusServiceHost.cs
- StringCollection.cs
- XamlBrushSerializer.cs
- RequestQueue.cs
- Expressions.cs
- DataFormat.cs
- EdmScalarPropertyAttribute.cs
- ToolTip.cs
- LicFileLicenseProvider.cs
- SqlDataSourceConfigureSortForm.cs
- ResXFileRef.cs
- InternalControlCollection.cs
- Pair.cs
- ClientSponsor.cs
- IndentedTextWriter.cs
- BindingManagerDataErrorEventArgs.cs
- BreakSafeBase.cs
- CompoundFileStreamReference.cs
- PropertyGridEditorPart.cs
- FixedDocumentSequencePaginator.cs
- SqlDataSourceCommandParser.cs
- BindingContext.cs
- MemoryPressure.cs
- EtwTrace.cs
- GradientPanel.cs
- RadioButton.cs
- TypeConverterAttribute.cs
- UrlPath.cs
- RootProjectionNode.cs
- Ipv6Element.cs
- BufferModeSettings.cs
- ExecutionEngineException.cs
- AssemblyCollection.cs
- IntegerCollectionEditor.cs
- CodeThrowExceptionStatement.cs
- WindowsServiceCredential.cs
- ToolboxBitmapAttribute.cs
- IncrementalReadDecoders.cs
- ResourceKey.cs
- Popup.cs
- ScrollBarAutomationPeer.cs
- CharUnicodeInfo.cs
- SettingsPropertyValue.cs
- TextEvent.cs
- SiteMapNodeCollection.cs
- CroppedBitmap.cs
- CapabilitiesPattern.cs
- CopyNamespacesAction.cs
- LayoutSettings.cs