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
- DataGridViewImageColumn.cs
- SystemFonts.cs
- SecurityHelper.cs
- StringUtil.cs
- __ComObject.cs
- RSAPKCS1SignatureFormatter.cs
- Base64Stream.cs
- base64Transforms.cs
- BaseUriHelper.cs
- DBSchemaTable.cs
- EntityKeyElement.cs
- PixelFormats.cs
- DataTableCollection.cs
- PolygonHotSpot.cs
- ProviderUtil.cs
- TimeManager.cs
- SqlDataReaderSmi.cs
- UnsafeCollabNativeMethods.cs
- InputLanguageEventArgs.cs
- ListViewPagedDataSource.cs
- CacheMemory.cs
- UserInitiatedNavigationPermission.cs
- ServiceProviders.cs
- PageWrapper.cs
- serverconfig.cs
- ToolStripProfessionalLowResolutionRenderer.cs
- BitmapDownload.cs
- GridViewCellAutomationPeer.cs
- Brush.cs
- RtfToXamlLexer.cs
- XmlSchemaValidator.cs
- TextPenaltyModule.cs
- StructuredTypeEmitter.cs
- SecureUICommand.cs
- TimelineCollection.cs
- NumericUpDownAcceleration.cs
- ModelFactory.cs
- XamlDesignerSerializationManager.cs
- QilInvokeLateBound.cs
- ClientSession.cs
- XamlTypeMapperSchemaContext.cs
- XmlAtomicValue.cs
- DirectoryInfo.cs
- CharEnumerator.cs
- IndentedWriter.cs
- RequestTimeoutManager.cs
- MemberCollection.cs
- AffineTransform3D.cs
- BorderGapMaskConverter.cs
- ClickablePoint.cs
- MembershipValidatePasswordEventArgs.cs
- ConfigurationManagerHelper.cs
- CustomErrorsSection.cs
- ZipIOExtraFieldPaddingElement.cs
- WorkflowDefinitionContext.cs
- XComponentModel.cs
- Monitor.cs
- EventBuilder.cs
- HyperLinkField.cs
- HttpListener.cs
- EventLogger.cs
- DesigntimeLicenseContext.cs
- SkipStoryboardToFill.cs
- Visual3DCollection.cs
- MatrixCamera.cs
- MultitargetUtil.cs
- _ChunkParse.cs
- FloaterParaClient.cs
- Schema.cs
- ProfileInfo.cs
- autovalidator.cs
- EmptyWithCancelationCheckWorkItem.cs
- HostProtectionPermission.cs
- ListView.cs
- SafeTimerHandle.cs
- HostProtectionException.cs
- XPathNavigatorKeyComparer.cs
- OuterGlowBitmapEffect.cs
- M3DUtil.cs
- XmlDataImplementation.cs
- StylusPointProperty.cs
- GeometryGroup.cs
- ChangeConflicts.cs
- BoundField.cs
- QilParameter.cs
- DataGridColumn.cs
- WebPartActionVerb.cs
- PartialCachingAttribute.cs
- SslStream.cs
- DBConnectionString.cs
- CqlGenerator.cs
- XmlWhitespace.cs
- UIElementPropertyUndoUnit.cs
- FreezableDefaultValueFactory.cs
- WindowsFormsSynchronizationContext.cs
- ToolStripSettings.cs
- ExpressionNormalizer.cs
- Size.cs
- LocationReferenceValue.cs
- WebPartConnectionsCloseVerb.cs