Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / MS / Internal / Annotations / Anchoring / TextSelectionProcessor.cs / 1 / 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
- DeploymentSection.cs
- CodeSnippetTypeMember.cs
- AudioDeviceOut.cs
- Compiler.cs
- TcpClientChannel.cs
- UniqueConstraint.cs
- Scheduler.cs
- EntityDataSourceValidationException.cs
- DialogResultConverter.cs
- RectConverter.cs
- ModelTreeEnumerator.cs
- ResXResourceWriter.cs
- CursorConverter.cs
- StreamGeometry.cs
- DateTimeFormatInfo.cs
- DataGridTemplateColumn.cs
- BaseValidator.cs
- KnownTypes.cs
- GridItem.cs
- SafeArrayTypeMismatchException.cs
- CatalogZoneBase.cs
- DisplayMemberTemplateSelector.cs
- CssTextWriter.cs
- DataGridViewBand.cs
- AssemblyCollection.cs
- PipeStream.cs
- CompilerScopeManager.cs
- SecurityContext.cs
- OutKeywords.cs
- EdmRelationshipRoleAttribute.cs
- EncoderBestFitFallback.cs
- UrlAuthorizationModule.cs
- EntityExpressionVisitor.cs
- Section.cs
- AggregationMinMaxHelpers.cs
- DataColumnMapping.cs
- ZipArchive.cs
- ResourceDisplayNameAttribute.cs
- BookmarkScopeHandle.cs
- Base64WriteStateInfo.cs
- FieldToken.cs
- Reference.cs
- ColorContextHelper.cs
- ApplyTemplatesAction.cs
- ExpressionPrefixAttribute.cs
- BitmapDecoder.cs
- ProxyFragment.cs
- ScriptResourceInfo.cs
- AutoResetEvent.cs
- PKCS1MaskGenerationMethod.cs
- ClientApiGenerator.cs
- Root.cs
- SmtpReplyReaderFactory.cs
- COM2DataTypeToManagedDataTypeConverter.cs
- WindowsGraphics2.cs
- X509UI.cs
- PasswordBoxAutomationPeer.cs
- ScriptReferenceBase.cs
- KeyGestureValueSerializer.cs
- JsonCollectionDataContract.cs
- SchemaComplexType.cs
- HttpWebRequestElement.cs
- AnnotationDocumentPaginator.cs
- SecurityKeyIdentifier.cs
- ListBoxAutomationPeer.cs
- SizeAnimationClockResource.cs
- BaseInfoTable.cs
- DocumentCollection.cs
- ObjectItemAssemblyLoader.cs
- InvokeProviderWrapper.cs
- RuntimeTransactionHandle.cs
- DataGridCell.cs
- UpWmlMobileTextWriter.cs
- QueryStringHandler.cs
- DetailsViewDeleteEventArgs.cs
- TemplateBindingExpression.cs
- HistoryEventArgs.cs
- MsmqBindingFilter.cs
- SecurityPolicySection.cs
- OdbcErrorCollection.cs
- FunctionQuery.cs
- ConfigXmlCDataSection.cs
- Graph.cs
- ListCollectionView.cs
- GACIdentityPermission.cs
- KeyValuePair.cs
- Inflater.cs
- TableLayoutCellPaintEventArgs.cs
- infer.cs
- SQLMembershipProvider.cs
- ErrorTolerantObjectWriter.cs
- SiteMapNodeItemEventArgs.cs
- DropAnimation.xaml.cs
- AsyncCodeActivityContext.cs
- ServiceElementCollection.cs
- ToolStripOverflowButton.cs
- MaskedTextProvider.cs
- DockAndAnchorLayout.cs
- CodeTypeParameter.cs
- MailMessageEventArgs.cs