Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / 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
- ErrorHandler.cs
- ProjectionPathSegment.cs
- DataGridViewRowDividerDoubleClickEventArgs.cs
- ResourceSet.cs
- SimpleBitVector32.cs
- ContentValidator.cs
- SchemaImporterExtensionElementCollection.cs
- ActiveXMessageFormatter.cs
- HtmlInputText.cs
- CallSiteBinder.cs
- HyperLinkColumn.cs
- ScrollableControl.cs
- SafePEFileHandle.cs
- XmlChildEnumerator.cs
- IconBitmapDecoder.cs
- MissingManifestResourceException.cs
- PublisherMembershipCondition.cs
- ExternalCalls.cs
- DataViewListener.cs
- DataGridViewRowCancelEventArgs.cs
- DynamicControlParameter.cs
- RelationshipNavigation.cs
- WinFormsUtils.cs
- Line.cs
- LinkButton.cs
- SQLInt16.cs
- DataGridViewTopRowAccessibleObject.cs
- cookieexception.cs
- ControlAdapter.cs
- HashMembershipCondition.cs
- UnSafeCharBuffer.cs
- SrgsElement.cs
- SQLBytes.cs
- CellLabel.cs
- CallTemplateAction.cs
- serverconfig.cs
- UIElementCollection.cs
- HMACSHA1.cs
- DispatcherOperation.cs
- DataTemplateSelector.cs
- TaiwanCalendar.cs
- CharKeyFrameCollection.cs
- PropertyTabChangedEvent.cs
- DockProviderWrapper.cs
- CodeBlockBuilder.cs
- CultureMapper.cs
- SqlDataSourceQueryEditorForm.cs
- MethodRental.cs
- DataAdapter.cs
- ReverseComparer.cs
- WorkflowQueue.cs
- MenuCommand.cs
- ListViewGroupItemCollection.cs
- SafeLibraryHandle.cs
- CancelEventArgs.cs
- GetKeyedHashRequest.cs
- ResourcesChangeInfo.cs
- FutureFactory.cs
- ChannelManagerBase.cs
- HotSpot.cs
- WorkflowDataContext.cs
- SymbolType.cs
- DateBoldEvent.cs
- SecurityKeyUsage.cs
- Qualifier.cs
- CompilerInfo.cs
- ClockController.cs
- Hashtable.cs
- ImmutableObjectAttribute.cs
- DateTimeParse.cs
- SecurityElement.cs
- LayoutExceptionEventArgs.cs
- XmlStringTable.cs
- WorkflowItemsPresenter.cs
- NameValuePermission.cs
- TreeNodeCollectionEditor.cs
- DataGridAddNewRow.cs
- UInt64Converter.cs
- GrammarBuilder.cs
- SystemFonts.cs
- BamlResourceDeserializer.cs
- PathFigureCollectionConverter.cs
- SignedXml.cs
- WinFormsSecurity.cs
- TrackingMemoryStream.cs
- SessionStateItemCollection.cs
- DictionaryCustomTypeDescriptor.cs
- StrongBox.cs
- EventListenerClientSide.cs
- SchemaDeclBase.cs
- ShapingEngine.cs
- ItemCheckedEvent.cs
- EdgeProfileValidation.cs
- ContainerParagraph.cs
- XmlSchemaSimpleContent.cs
- UnauthorizedWebPart.cs
- PropertyEmitter.cs
- DrawingDrawingContext.cs
- categoryentry.cs
- ConstructorArgumentAttribute.cs