Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Controls / TextAdaptor.cs / 2 / TextAdaptor.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Text Object Models Text pattern provider // Spec for TextPattern at [....]/sites/uiauto/Shared%20Documents/TextPatternSpecM8.doc // Spec for Text Object Model (TOM) at [....]/uis/TextBox%20and%20RichTextBox/Text%20Object%20Model.doc // // History: // 03/15/2004 : [....] - created // 09/07/2004 : [....] - refactored // 01/20/2004 : [....] - refactored // //--------------------------------------------------------------------------- using System; // Exception using System.Collections.Generic; // Listusing System.Collections.ObjectModel; // ReadOnlyCollection using System.Security; // SecurityCritical, ... using System.Windows; // PresentationSource using System.Windows.Automation; // SupportedTextSelection using System.Windows.Automation.Peers; // AutomationPeer using System.Windows.Automation.Provider; // ITextProvider using System.Windows.Controls.Primitives; // IScrollInfo using System.Windows.Documents; // ITextContainer using System.Windows.Media; // Visual using MS.Internal.Documents; // MultiPageTextView namespace MS.Internal.Automation { /// /// Represents a text provider that supports the text pattern across Text Object /// Model based Text Controls. /// internal class TextAdaptor : ITextProvider, IDisposable { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Constructor /// /// Automation Peer representing element for the ui scope of the text /// ITextContainer internal TextAdaptor(AutomationPeer textPeer, ITextContainer textContainer) { Invariant.Assert(textContainer != null, "Invalid ITextContainer"); Invariant.Assert(textPeer is TextAutomationPeer || textPeer is ContentTextAutomationPeer, "Invalid AutomationPeer"); _textPeer = textPeer; _textContainer = textContainer; _textContainer.Changed += new TextContainerChangedEventHandler(OnTextContainerChanged); if (_textContainer.TextSelection != null) { _textContainer.TextSelection.Changed += new EventHandler(OnTextSelectionChanged); } } ////// Dispose. /// public void Dispose() { if (_textContainer != null && _textContainer.TextSelection != null) { _textContainer.TextSelection.Changed -= new EventHandler(OnTextSelectionChanged); } } #endregion Constructors //-------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods ////// Retrieves the bounding rectangles for the text lines of a given range. /// /// Start of range to measure /// End of range to measure /// Specifies whether the caller wants the full bounds (false) or the bounds of visible portions /// of the viewable line only ('true') /// Requests the results in screen coordinates ///An array of bounding rectangles for each line or portion of a line within the client area of the text provider. /// No bounding rectangles will be returned for lines that are empty or scrolled out of view. Note that even though a /// bounding rectangle is returned the corresponding text may not be visible due to overlapping windows. /// This will not return null, but may return an empty array. internal Rect[] GetBoundingRectangles(ITextPointer start, ITextPointer end, bool clipToView, bool transformToScreen) { ITextView textView = GetUpdatedTextView(); if (textView == null) { return new Rect[0]; } // If start/end positions are not in the visible range, move them to the first/last visible positions. ReadOnlyCollectiontextSegments = textView.TextSegments; if (textSegments.Count > 0) { if (!textView.Contains(start) && start.CompareTo(textSegments[0].Start) < 0) { start = textSegments[0].Start.CreatePointer(); ; } if (!textView.Contains(end) && end.CompareTo(textSegments[textSegments.Count-1].End) > 0) { end = textSegments[textSegments.Count - 1].End.CreatePointer(); } } if (!textView.Contains(start) || !textView.Contains(end)) { return new Rect[0]; } TextRangeAdaptor.MoveToInsertionPosition(start, LogicalDirection.Forward); TextRangeAdaptor.MoveToInsertionPosition(end, LogicalDirection.Backward); Rect visibleRect = Rect.Empty; if (clipToView) { visibleRect = GetVisibleRectangle(textView); // If clipping into view and visible rect is empty, return. if (visibleRect.IsEmpty) { return new Rect[0]; } } List rectangles = new List (); ITextPointer position = start.CreatePointer(); while (position.CompareTo(end) < 0) { TextSegment lineRange = textView.GetLineRange(position); if (!lineRange.IsNull) { // Since range is limited to just one line, GetTightBoundingGeometry will return tight bounding // rectangle for given range. It will also work correctly with bidi text. ITextPointer first = (lineRange.Start.CompareTo(start) <= 0) ? start : lineRange.Start; ITextPointer last = (lineRange.End.CompareTo(end) >= 0) ? end : lineRange.End; Rect lineRect = Rect.Empty; Geometry geometry = textView.GetTightBoundingGeometryFromTextPositions(first, last); if (geometry != null) { lineRect = geometry.Bounds; if (clipToView) { lineRect.Intersect(visibleRect); } if (!lineRect.IsEmpty) { if (transformToScreen) { lineRect = new Rect(ClientToScreen(lineRect.TopLeft, textView.RenderScope), ClientToScreen(lineRect.BottomRight, textView.RenderScope)); } rectangles.Add(lineRect); } } } if (position.MoveToLineBoundary(1) == 0) { position = end; } } return rectangles.ToArray(); } /// /// Retrieves associated TextView. If TextView is not valid, tries to update its layout. /// internal ITextView GetUpdatedTextView() { ITextView textView = _textContainer.TextView; if (textView != null) { if (!textView.IsValid) { if (!textView.Validate()) { textView = null; } if (textView != null && !textView.IsValid) { textView = null; } } } return textView; } ////// Changes text selection on the element /// /// Start of range to select /// End of range to select ///Automation clients as well as the internal caller of this method (a TextRangeAdapter object) are supposed /// to verify whether the provider supports text selection by calling SupportsTextSelection first. /// The internal caller is responsible for raising an InvalidOperationException upon the Automation client' attempt /// to change selection when it's not supported by the provider internal void Select(ITextPointer start, ITextPointer end) { // Update the selection range if (_textContainer.TextSelection != null) { _textContainer.TextSelection.Select(start, end); } } ////// This helper method is used by TextRangeAdaptor to bring the range into view /// through multiple nested scroll providers. /// internal void ScrollIntoView(ITextPointer start, ITextPointer end, bool alignToTop) { // Calculate the bounding rectangle for the range Rect rangeBounds = Rect.Empty; Rect[] lineBounds = GetBoundingRectangles(start, end, false, false); foreach (Rect rect in lineBounds) { rangeBounds.Union(rect); } ITextView textView = GetUpdatedTextView(); if (textView != null && !rangeBounds.IsEmpty) { // Find out the visible portion of the range. Rect visibleRect = GetVisibleRectangle(textView); Rect rangeVisibleBounds = Rect.Intersect(rangeBounds, visibleRect); if (rangeVisibleBounds == rangeBounds) { // The range is already in the view. It's probably not aligned as requested, // but who cares since it's entirely visible anyway. return; } // Ensure the visibility of the range. // BringIntoView will do most of the magic except the very first scroll // in order to satisfy the requested alignment. UIElement renderScope = textView.RenderScope; Visual visual = renderScope; while (visual != null) { IScrollInfo isi = visual as IScrollInfo; if (isi != null) { // Transform the bounding rectangle into the IScrollInfo coordinates. if (visual != renderScope) { GeneralTransform childToParent = renderScope.TransformToAncestor(visual); rangeBounds = childToParent.TransformBounds(rangeBounds); } if (isi.CanHorizontallyScroll) { isi.SetHorizontalOffset(alignToTop ? rangeBounds.Left : (rangeBounds.Right - isi.ViewportWidth)); } if (isi.CanVerticallyScroll) { isi.SetVerticalOffset(alignToTop ? rangeBounds.Top : (rangeBounds.Bottom - isi.ViewportHeight)); } break; } visual = VisualTreeHelper.GetParent(visual) as Visual; } FrameworkElement fe = renderScope as FrameworkElement; if (fe != null) { fe.BringIntoView(rangeVisibleBounds); } } else { // If failed to retrive range bounds, try to Bring into view closes element. ITextPointer pointer = alignToTop ? start.CreatePointer() : end.CreatePointer(); pointer.MoveToElementEdge(alignToTop ? ElementEdge.AfterStart : ElementEdge.AfterEnd); FrameworkContentElement element = pointer.GetAdjacentElement(LogicalDirection.Backward) as FrameworkContentElement; if (element != null) { element.BringIntoView(); } } } #endregion Internal Methods //-------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------- #region Private Methods ////// Notify about content changes. /// private void OnTextContainerChanged(object sender, TextContainerChangedEventArgs e) { _textPeer.RaiseAutomationEvent(AutomationEvents.TextPatternOnTextChanged); } ////// Notify about selection changes. /// private void OnTextSelectionChanged(object sender, EventArgs e) { _textPeer.RaiseAutomationEvent(AutomationEvents.TextPatternOnTextSelectionChanged); } ////// Computes the bounds of the render scope area visible through all nested scroll areas. /// private Rect GetVisibleRectangle(ITextView textView) { Rect visibleRect = new Rect(textView.RenderScope.RenderSize); Visual visual = VisualTreeHelper.GetParent(textView.RenderScope) as Visual; while (visual != null && visibleRect != Rect.Empty) { if (VisualTreeHelper.GetClip(visual) != null) { GeneralTransform transform = textView.RenderScope.TransformToAncestor(visual).Inverse; // Safer version of transform to descendent (doing the inverse ourself), // we want the rect inside of our space. (Which is always rectangular and much nicer to work with). if (transform != null) { Rect rectBounds = VisualTreeHelper.GetClip(visual).Bounds; rectBounds = transform.TransformBounds(rectBounds); visibleRect.Intersect(rectBounds); } else { // No visibility if non-invertable transform exists. visibleRect = Rect.Empty; } } visual = VisualTreeHelper.GetParent(visual) as Visual; } return visibleRect; } ////// Convert a point from "client" coordinate space of a window into /// the coordinate space of the screen. /// ////// Critical: This code calls into PresentationSource to get HwndSource /// TreatAsSafe: This code is not exposing any critical information, at the same time /// [SecurityCritical, SecurityTreatAsSafe] private Point ClientToScreen(Point point, Visual visual) { PresentationSource presentationSource = PresentationSource.CriticalFromVisual(visual); if (presentationSource != null) { GeneralTransform transform = visual.TransformToAncestor(presentationSource.RootVisual); if (transform != null) { point = transform.Transform(point); } } return PointUtil.ClientToScreen(point, presentationSource); } ////// Convert a point from the coordinate space of the screen into /// the "client" coordinate space of a window. /// ////// Critical: This code calls into PresentationSource to get HwndSource /// TreatAsSafe: This code is not exposing any critical information, at the same time /// [SecurityCritical, SecurityTreatAsSafe] private Point ScreenToClient(Point point, Visual visual) { PresentationSource presentationSource = PresentationSource.CriticalFromVisual(visual); point = PointUtil.ScreenToClient(point, presentationSource); if (presentationSource != null) { GeneralTransform transform = visual.TransformToAncestor(presentationSource.RootVisual); if (transform != null) { transform = transform.Inverse; if (transform != null) { point = transform.Transform(point); } } } return point; } #endregion Private Methods //------------------------------------------------------------------- // // Private Fields // //-------------------------------------------------------------------- #region Private fields private AutomationPeer _textPeer; private ITextContainer _textContainer; #endregion Private Fields //------------------------------------------------------------------- // // ITextProvider // //------------------------------------------------------------------- #region ITextProvider implementation ////// Retrieves the current selection. For providers that have the concept of /// text selection the provider should implement this method and also return /// true for the SupportsTextSelection property below. Otherwise this method /// should throw an InvalidOperation exception. /// For providers that support multiple disjoint selection, this should return /// an array of all the currently selected ranges. Providers that don't support /// multiple disjoint selection should just return an array containing a single /// range. /// ///The range of text that is selected, or possibly null if there is /// no selection. ITextRangeProvider[] ITextProvider.GetSelection() { ITextRange selection = _textContainer.TextSelection; if (selection == null) { throw new InvalidOperationException(SR.Get(SRID.TextProvider_TextSelectionNotSupported)); } return new ITextRangeProvider[] { new TextRangeAdaptor(this, selection.Start, selection.End, _textPeer) }; } ////// Retrieves the visible ranges of text. /// ///The ranges of text that are visible, or possibly an empty array if there is /// no visible text whatsoever. Text in the range may still be obscured by an overlapping /// window. Also, portions /// of the range at the beginning, in the middle, or at the end may not be visible /// because they are scrolled off to the side. /// Providers should ensure they return at most a range from the beginning of the first /// line with portions visible through the end of the last line with portions visible. ITextRangeProvider[] ITextProvider.GetVisibleRanges() { ITextRangeProvider[] ranges = null; ITextView textView = GetUpdatedTextView(); if (textView != null) { ListvisibleTextSegments = new List (); // Get visible portion of the document. // if (textView is MultiPageTextView) { // For MultiPageTextView assume that all current pages are entirely visible. visibleTextSegments.AddRange(textView.TextSegments); } else { // For all others TextViews get visible rectangle and hittest TopLeft and // BottomRight points to retrieve visible range. // Find out the bounds of the area visible through all nested scroll areas Rect visibleRect = GetVisibleRectangle(textView); if (!visibleRect.IsEmpty) { ITextPointer visibleStart = textView.GetTextPositionFromPoint(visibleRect.TopLeft, true); ITextPointer visibleEnd = textView.GetTextPositionFromPoint(visibleRect.BottomRight, true); visibleTextSegments.Add(new TextSegment(visibleStart, visibleEnd, true)); } } // Create collection of TextRangeProviders for visible ranges. if (visibleTextSegments.Count > 0) { ranges = new ITextRangeProvider[visibleTextSegments.Count]; for (int i = 0; i < visibleTextSegments.Count; i++) { ranges[i] = new TextRangeAdaptor(this, visibleTextSegments[i].Start, visibleTextSegments[i].End, _textPeer); } } } // If no text is visible in the control, return the degenerate text range // (empty range) at the beginning of the document. if (ranges == null) { ranges = new ITextRangeProvider[] { new TextRangeAdaptor(this, _textContainer.Start, _textContainer.Start, _textPeer) }; } return ranges; } /// /// Retrieves the range of a child object. /// /// The child element. A provider should check that the /// passed element is a child of the text container, and should throw an /// InvalidOperationException if it is not. ///A range that spans the child element. ITextRangeProvider ITextProvider.RangeFromChild(IRawElementProviderSimple childElementProvider) { if (childElementProvider == null) { throw new ArgumentNullException("childElementProvider"); } // Retrieve DependencyObject from AutomationElement DependencyObject childElement; if (_textPeer is TextAutomationPeer) { childElement = ((TextAutomationPeer)_textPeer).ElementFromProvider(childElementProvider); } else { childElement = ((ContentTextAutomationPeer)_textPeer).ElementFromProvider(childElementProvider); } TextRangeAdaptor range = null; if (childElement != null) { ITextPointer rangeStart = null; ITextPointer rangeEnd = null; // Retrieve start and end positions for given element. // If element is TextElement, retrieve its Element Start and End positions. // If element is UIElement hosted by UIContainer (Inlien of Block), // retrieve content Start and End positions of the container. // Otherwise scan ITextContainer to find a range for given element. if (childElement is TextElement) { rangeStart = ((TextElement)childElement).ElementStart; rangeEnd = ((TextElement)childElement).ElementEnd; } else { DependencyObject parent = LogicalTreeHelper.GetParent(childElement); if (parent is InlineUIContainer || parent is BlockUIContainer) { rangeStart = ((TextElement)parent).ContentStart; rangeEnd = ((TextElement)parent).ContentEnd; } else { ITextPointer position = _textContainer.Start.CreatePointer(); while (position.CompareTo(_textContainer.End) < 0) { TextPointerContext context = position.GetPointerContext(LogicalDirection.Forward); if (context == TextPointerContext.ElementStart) { if (childElement == position.GetAdjacentElement(LogicalDirection.Forward)) { rangeStart = position.CreatePointer(LogicalDirection.Forward); position.MoveToElementEdge(ElementEdge.AfterEnd); rangeEnd = position.CreatePointer(LogicalDirection.Backward); break; } } else if (context == TextPointerContext.EmbeddedElement) { if (childElement == position.GetAdjacentElement(LogicalDirection.Forward)) { rangeStart = position.CreatePointer(LogicalDirection.Forward); position.MoveToNextContextPosition(LogicalDirection.Forward); rangeEnd = position.CreatePointer(LogicalDirection.Backward); break; } } position.MoveToNextContextPosition(LogicalDirection.Forward); } } } // Create range if (rangeStart != null && rangeEnd != null) { range = new TextRangeAdaptor(this, rangeStart, rangeEnd, _textPeer); } } if (range == null) { throw new InvalidOperationException(SR.Get(SRID.TextProvider_InvalidChildElement)); } return range; } ////// Finds the degenerate range nearest to a screen coordinate. /// /// The location in screen coordinates. /// The provider should check that the coordinates are within the client /// area of the provider, and should throw an InvalidOperation exception /// if they are not. ///A degenerate range nearest the specified location. ITextRangeProvider ITextProvider.RangeFromPoint(Point location) { TextRangeAdaptor range = null; ITextView textView = GetUpdatedTextView(); if (textView != null) { // Convert the screen point to the element space coordinates. location = ScreenToClient(location, textView.RenderScope); ITextPointer position = textView.GetTextPositionFromPoint(location, true); if (position != null) { range = new TextRangeAdaptor(this, position, position, _textPeer); } } if (range == null) { throw new ArgumentException(SR.Get(SRID.TextProvider_InvalidPoint)); } return range; } ////// A text range that encloses the main text of the document. Some auxillary text such as /// headers, footnotes, or annotations may not be included. /// ITextRangeProvider ITextProvider.DocumentRange { get { return new TextRangeAdaptor(this, _textContainer.Start, _textContainer.End, _textPeer); } } ////// True if the text container supports text selection. If the provider returns false then /// it should throw InvalidOperation exceptions for ITextProvider.GetSelection and /// ITextRangeProvider.Select. /// SupportedTextSelection ITextProvider.SupportedTextSelection { get { return (_textContainer.TextSelection == null) ? SupportedTextSelection.None : SupportedTextSelection.Single; } } #endregion ITextProvider implementation } } // 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
- TextLine.cs
- ControlCollection.cs
- RegexGroupCollection.cs
- Geometry3D.cs
- WebConfigurationHost.cs
- DataBoundControlHelper.cs
- ColorContext.cs
- TextParaLineResult.cs
- HttpHostedTransportConfiguration.cs
- FormatSettings.cs
- PaperSource.cs
- BamlResourceSerializer.cs
- TextBoxRenderer.cs
- CalendarAutomationPeer.cs
- DataGridViewSelectedCellCollection.cs
- DataTableExtensions.cs
- ImageListDesigner.cs
- ElementHostAutomationPeer.cs
- BaseServiceProvider.cs
- DataGridViewColumn.cs
- ObjectPersistData.cs
- ISAPIWorkerRequest.cs
- MouseActionConverter.cs
- Stack.cs
- MetadataArtifactLoader.cs
- XmlTextAttribute.cs
- SmtpNetworkElement.cs
- ScriptResourceInfo.cs
- HtmlUtf8RawTextWriter.cs
- Compiler.cs
- ActiveDocumentEvent.cs
- formatstringdialog.cs
- SafeCryptoHandles.cs
- UpdatePanelTriggerCollection.cs
- TextBoxDesigner.cs
- Animatable.cs
- ObjectListSelectEventArgs.cs
- NamespaceImport.cs
- COM2PropertyDescriptor.cs
- BitmapMetadata.cs
- DefaultBinder.cs
- ConfigXmlElement.cs
- _AuthenticationState.cs
- FrameSecurityDescriptor.cs
- safex509handles.cs
- __TransparentProxy.cs
- TypeDescriptionProviderAttribute.cs
- RenderData.cs
- DispatcherOperation.cs
- NumericUpDownAcceleration.cs
- Variant.cs
- RequestCachingSection.cs
- Int16AnimationBase.cs
- TraceHandlerErrorFormatter.cs
- FrameworkReadOnlyPropertyMetadata.cs
- RelativeSource.cs
- EntityViewGenerationConstants.cs
- WindowsListViewSubItem.cs
- SpecialFolderEnumConverter.cs
- TransformerConfigurationWizardBase.cs
- OpacityConverter.cs
- SqlExpander.cs
- SHA1.cs
- URLAttribute.cs
- SecurityException.cs
- ValidationPropertyAttribute.cs
- UrlMappingsSection.cs
- PackWebRequest.cs
- DeleteMemberBinder.cs
- HttpClientChannel.cs
- DesignerVerbCollection.cs
- GeneratedContractType.cs
- MetaModel.cs
- ProvideValueServiceProvider.cs
- DependencyPropertyHelper.cs
- XmlSchemaAnnotation.cs
- PrintPageEvent.cs
- ListenDesigner.cs
- PageCache.cs
- StackOverflowException.cs
- RawStylusInput.cs
- PassportAuthenticationModule.cs
- HyperLink.cs
- ICspAsymmetricAlgorithm.cs
- UnaryOperationBinder.cs
- LineServicesCallbacks.cs
- PeerNameRegistration.cs
- TimeEnumHelper.cs
- ToolboxCategory.cs
- CategoryGridEntry.cs
- FontConverter.cs
- Table.cs
- CheckBoxAutomationPeer.cs
- RelationshipConverter.cs
- ChildTable.cs
- DataBoundControl.cs
- ResolveInfo.cs
- BatchServiceHost.cs
- ContentTextAutomationPeer.cs
- TypeFieldSchema.cs