Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / MS / Internal / Annotations / Anchoring / FixedTextSelectionProcessor.cs / 1 / FixedTextSelectionProcessor.cs
//------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // FixedTextSelectionProcessor uses TextAnchors to represent portions // of text that are anchors. It produces FixedTextRange locator parts that are designed // specifically for use inside the DocumentViewer control. This locator part contains the // page number and the start and end points of the text selection. // FixedTextSelectionProcessor converts the text selection to FixedTextRange // // Spec: http://team/sites/ag/Specifications/Anchoring%20to%20text%20in%20paginated%20docs.doc // // History: // 09/29/2004: ssimova: Created // 12/07/2004: rruiz: Updated processor to work on new DocumentViewer //----------------------------------------------------------------------------- using System; using System.IO; using System.Windows; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; 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; using MS.Internal.PtsHost; namespace MS.Internal.Annotations.Anchoring { ////// FixedTextSelectionProcessor uses TextAnchors to represent portions /// of text that are anchors. It produces locator parts that /// represent these TextRanges by beginning and end position /// internal class FixedTextSelectionProcessor : SelectionProcessor { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Creates an instance of FixedTextSelectionProcessor. /// public FixedTextSelectionProcessor() { } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Merges the two anchors into one, if possible. It does not require /// the anchors to be connected. All this method does is to create a /// TextAnchor that spans the two anchors. /// /// anchor to merge. Must be a TextAnchor. /// other anchor to merge. Must be a TextAnchor. /// new anchor that contains the data from both /// anchor1 and anchor2 ///true if the anchors were merged, false otherwise /// public override bool MergeSelections(Object anchor1, Object anchor2, out Object newAnchor) { return TextSelectionHelper.MergeSelections(anchor1, anchor2, out newAnchor); } ////// Generates FixedPageProxy objects for each page, spaned by the selection /// /// the selection to examine. Must implement ITextRange ///a list of FixedPageProxy objects, corresponding to each page spanned by the selection; never returns /// null ///selection is null ///selection is of wrong type ///selection start or end point can not be resolved to a page public override IListGetSelectedNodes(Object selection) { IList textSegments = CheckSelection(selection); IList pageEl = new List (); Point start; Point end; foreach (TextSegment segment in textSegments) { int startPage = int.MinValue; ITextPointer startPointer = segment.Start.CreatePointer(LogicalDirection.Forward); TextSelectionHelper.GetPointerPage(startPointer, out startPage); start = TextSelectionHelper.GetPointForPointer(startPointer); if (startPage == int.MinValue) throw new ArgumentException(SR.Get(SRID.SelectionDoesNotResolveToAPage, "start"), "selection"); int endPage = int.MinValue; ITextPointer endPointer = segment.End.CreatePointer(LogicalDirection.Backward); TextSelectionHelper.GetPointerPage(endPointer, out endPage); end = TextSelectionHelper.GetPointForPointer(endPointer); if (endPage == int.MinValue) throw new ArgumentException(SR.Get(SRID.SelectionDoesNotResolveToAPage, "end"), "selection"); int firstPage = pageEl.Count; int numOfPages = endPage - startPage; Debug.Assert(numOfPages >= 0, "start page number is bigger than the end page number"); // If the first page of this segment already has an FPP, then use that one for an additional segment int i = 0; if (pageEl.Count > 0 && ((FixedPageProxy)pageEl[pageEl.Count - 1]).Page == startPage) { firstPage--; // use the existing one from the list as the first i++; // make 1 fewer FPPs } for (; i <= numOfPages; i++) { pageEl.Add(new FixedPageProxy(segment.Start.TextContainer.Parent, startPage + i)); } // If entire segment is on one page set both start/end on that page if (numOfPages == 0) { ((FixedPageProxy)pageEl[firstPage]).Segments.Add(new PointSegment(start, end)); } else { // otherwise set start on the first page and end on the last page ((FixedPageProxy)pageEl[firstPage]).Segments.Add(new PointSegment(start, PointSegment.NotAPoint)); ((FixedPageProxy)pageEl[firstPage + numOfPages]).Segments.Add(new PointSegment(PointSegment.NotAPoint, end)); } } return pageEl; } /// /// Gets the parent element of this selection. The parent element is the /// FixedPage that contains selection.Start TextPointer. /// /// the selection to examine. Must implement ITextRange ///the parent element of the selection; can be null ///selection is null ///selection is of wrong type public override UIElement GetParent(Object selection) { CheckAnchor(selection); return TextSelectionHelper.GetParent(selection); } ////// Gets the anchor point for the selection. This is the Point that corresponds /// to the start position of the selection /// /// the selection to examine. Must implement ITextRange ///the anchor point of the selection; can be (double.NaN, double.NaN) if the /// selection start point is not contained in a document viewer ///selection is null ///selection is of wrong type public override Point GetAnchorPoint(Object selection) { CheckAnchor(selection); return TextSelectionHelper.GetAnchorPoint(selection); } ////// Creates one locator part representing part of the selection /// that lies within start node /// /// the selection that is being processed. Must implement ITextRange /// The FixedPageProxy object, representing one page of the document ///A list containing one FixedTextRange locator part ///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"); CheckSelection(selection); FixedPageProxy fp = startNode as FixedPageProxy; if (fp == null) throw new ArgumentException(SR.Get(SRID.StartNodeMustBeFixedPageProxy), "startNode"); ContentLocatorPart part = new ContentLocatorPart(FixedTextElementName); if (fp.Segments.Count == 0) { part.NameValuePairs.Add(TextSelectionProcessor.CountAttribute, 1.ToString(NumberFormatInfo.InvariantInfo)); part.NameValuePairs.Add(TextSelectionProcessor.SegmentAttribute + 0.ToString(NumberFormatInfo.InvariantInfo), ",,,"); } else { part.NameValuePairs.Add(TextSelectionProcessor.CountAttribute, fp.Segments.Count.ToString(NumberFormatInfo.InvariantInfo)); for (int i = 0; i < fp.Segments.Count; i++) { string value = ""; if (!double.IsNaN(fp.Segments[i].Start.X)) { value += fp.Segments[i].Start.X.ToString(NumberFormatInfo.InvariantInfo) + TextSelectionProcessor.Separator[0] + fp.Segments[i].Start.Y.ToString(NumberFormatInfo.InvariantInfo); } else { value += TextSelectionProcessor.Separator[0]; } value += TextSelectionProcessor.Separator[0]; if (!double.IsNaN(fp.Segments[i].End.X)) { value += fp.Segments[i].End.X.ToString(NumberFormatInfo.InvariantInfo) + TextSelectionProcessor.Separator[0] + fp.Segments[i].End.Y.ToString(NumberFormatInfo.InvariantInfo); } else { value += TextSelectionProcessor.Separator[0]; } part.NameValuePairs.Add(TextSelectionProcessor.SegmentAttribute + i.ToString(NumberFormatInfo.InvariantInfo), value); } } List res = new List (1); res.Add(part); return res; } /// /// Creates a TextRange object spanning the portion of 'startNode' /// specified by 'locatorPart'. /// /// FixedTextRange locator part specifying start and end point of /// the TextRange /// the FixedPage containing this locator part /// set to AttachmentLevel.Full if the FixedPage for the locator /// part was found, AttachmentLevel.Unresolved otherwise ///a TextRange spanning the text between start end end point in the FixedTextRange /// locator part /// , null if selection described by locator part could not be /// recreated ///locatorPart or startNode are /// null ///locatorPart is of the incorrect type ///startNode is not a FixedPage ///startNode does not belong to the DocumentViewer public override Object ResolveLocatorPart(ContentLocatorPart locatorPart, DependencyObject startNode, out AttachmentLevel attachmentLevel) { if (startNode == null) throw new ArgumentNullException("startNode"); DocumentPage docPage = null; FixedPage page = startNode as FixedPage; if (page != null) { docPage = GetDocumentPage(page); } else { // If we were passed a DPV because we are walking the visual tree, // extract the DocumentPage from it; its TextView will be used to // turn coordinates into text positions DocumentPageView dpv = startNode as DocumentPageView; if (dpv != null) { docPage = dpv.DocumentPage as FixedDocumentPage; if (docPage == null) { docPage = dpv.DocumentPage as FixedDocumentSequenceDocumentPage; } } } if (docPage == null) { throw new ArgumentException(SR.Get(SRID.StartNodeMustBeDocumentPageViewOrFixedPage), "startNode"); } if (locatorPart == null) throw new ArgumentNullException("locatorPart"); attachmentLevel = AttachmentLevel.Unresolved; ITextView tv = (ITextView)((IServiceProvider)docPage).GetService(typeof(ITextView)); Debug.Assert(tv != null); ReadOnlyCollectionts = tv.TextSegments; //check first if a TextRange can be generated if (ts == null || ts.Count <= 0) return null; TextAnchor resolvedAnchor = new TextAnchor(); if (docPage != null) { string stringCount = locatorPart.NameValuePairs["Count"]; if (stringCount == null) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.CountAttribute)); int count = Int32.Parse(stringCount, NumberFormatInfo.InvariantInfo); for(int i = 0; i < count; i++) { // First we extract the start and end Point from the locator part. Point start; Point end; GetLocatorPartSegmentValues(locatorPart, i, out start, out end); //calulate start ITextPointer ITextPointer segStart; if (double.IsNaN(start.X) || double.IsNaN(start.Y)) { //get start of the page segStart = FindStartVisibleTextPointer(docPage); } else { //convert Point to TextPointer segStart = tv.GetTextPositionFromPoint(start, true); } if (segStart == null) { //selStart can be null if there are no insertion points on this page continue; } //calulate end ITextPointer ITextPointer segEnd; if (double.IsNaN(end.X) || double.IsNaN(end.Y)) { segEnd = FindEndVisibleTextPointer(docPage); } else { //convert Point to TextPointer segEnd = tv.GetTextPositionFromPoint(end, true); } //end TP can not be null when start is not Invariant.Assert(segEnd != null, "end TP is null when start TP is not"); attachmentLevel = AttachmentLevel.Full; // Not always true right? resolvedAnchor.AddTextSegment(segStart, segEnd); } } if (resolvedAnchor.TextSegments.Count > 0) return resolvedAnchor; else return null; } /// /// 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 // //----------------------------------------------------- //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods private DocumentPage GetDocumentPage(FixedPage page) { Invariant.Assert(page != null); DocumentPage docPage = null; PageContent content = page.Parent as PageContent; if (content != null) { FixedDocument document = content.Parent as FixedDocument; // If the document is part of a FixedDocumentSequence then we want to get the // FixedDocumentSequenceDocumentPage for the FixedPage (cause its TextView is // the one we want to use). FixedDocumentSequence sequence = document.Parent as FixedDocumentSequence; if (sequence != null) { docPage = sequence.GetPage(document, document.GetIndexOfPage(page)); } else { docPage = document.GetPage(document.GetIndexOfPage(page)); } } return docPage; } ////// Checks if the selection object satisfies the requirements /// for this processor /// /// selection ///ITextRange interface, implemented by the object private IListCheckSelection(object selection) { if (selection == null) throw new ArgumentNullException("selection"); IList textSegments = null; ITextPointer start = null; ITextRange textRange = selection as ITextRange; if (textRange != null) { start = textRange.Start; textSegments = textRange.TextSegments; } else { TextAnchor anchor = selection as TextAnchor; if (anchor != null) { start = anchor.Start; textSegments = anchor.TextSegments; } else { throw new ArgumentException(SR.Get(SRID.WrongSelectionType), "selection: type=" + selection.GetType().ToString()); } } if (!(start.TextContainer is FixedTextContainer || start.TextContainer is DocumentSequenceTextContainer)) throw new ArgumentException(SR.Get(SRID.WrongSelectionType), "selection: type=" + selection.GetType().ToString()); return textSegments; } /// /// Checks if the selection object satisfies the requirements /// for this processor /// /// selection ///ITextRange interface, implemented by the object private TextAnchor CheckAnchor(object selection) { if (selection == null) throw new ArgumentNullException("selection"); TextAnchor anchor = selection as TextAnchor; if (anchor == null || !(anchor.Start.TextContainer is FixedTextContainer || anchor.Start.TextContainer is DocumentSequenceTextContainer)) { throw new ArgumentException(SR.Get(SRID.WrongSelectionType), "selection: type=" + selection.GetType().ToString()); } return anchor; } ////// Extracts the values of attributes from a locator part. /// /// the locator part to extract values from /// number of segment value to retrieve /// the start point value based on StartXAttribute and StartYAttribute values /// the end point value based on EndXAttribyte and EndYattribute values private void GetLocatorPartSegmentValues(ContentLocatorPart locatorPart, int segmentNumber, out Point start, out Point end) { if (locatorPart == null) throw new ArgumentNullException("locatorPart"); if (FixedTextElementName != locatorPart.PartType) throw new ArgumentException(SR.Get(SRID.IncorrectLocatorPartType, locatorPart.PartType.Namespace + ":" + locatorPart.PartType.Name), "locatorPart"); string segmentValue = locatorPart.NameValuePairs[TextSelectionProcessor.SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo)]; if (segmentValue == null) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo))); string[] values = segmentValue.Split(TextSelectionProcessor.Separator); if (values.Length != 4) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo))); start = GetPoint(values[0], values[1]); end = GetPoint(values[2], values[3]); } ////// Calculate Point out of string X and Y values /// /// x string value /// y string value ///private Point GetPoint(string xstr, string ystr) { Point point; if (xstr != null && !String.IsNullOrEmpty(xstr.Trim()) && ystr != null && !String.IsNullOrEmpty(ystr.Trim())) { double x = Double.Parse(xstr, NumberFormatInfo.InvariantInfo); double y = Double.Parse(ystr, NumberFormatInfo.InvariantInfo); point = new Point(x, y); } else { point = new Point(double.NaN, double.NaN); } return point; } /// /// Gets the first visible TP on a DocumentPage /// /// document page ///The first visible TP or null if no visible TP on this page private static ITextPointer FindStartVisibleTextPointer(DocumentPage documentPage) { ITextPointer start, end; if (!GetTextViewRange(documentPage, out start, out end)) return null; if (!start.IsAtInsertionPosition && !start.MoveToNextInsertionPosition(LogicalDirection.Forward)) { //there is no insertion point in this direction return null; } //check if it is outside of the page if (start.CompareTo(end) > 0) return null; return start; } ////// Gets the last visible TP on a DocumentPage /// /// document page ///The last visible TP or null if no visible TP on the page private static ITextPointer FindEndVisibleTextPointer(DocumentPage documentPage) { ITextPointer start, end; if (!GetTextViewRange(documentPage, out start, out end)) return null; if (!end.IsAtInsertionPosition && !end.MoveToNextInsertionPosition(LogicalDirection.Backward)) { //there is no insertion point in this direction return null; } //check if it is outside of the page if (start.CompareTo(end) > 0) return null; return end; } ////// Gets first and last TP on a documentPage. /// /// the document page /// start TP /// end TP ///true if there aretext segments on this page, otherwise false private static bool GetTextViewRange(DocumentPage documentPage, out ITextPointer start, out ITextPointer end) { ITextView textView; start = end = null; // Missing pages can't produce TextPointers Invariant.Assert(documentPage != DocumentPage.Missing); textView = ((IServiceProvider)documentPage).GetService(typeof(ITextView)) as ITextView; Invariant.Assert(textView != null, "DocumentPage didn't provide a TextView."); //check if there is any content if ((textView.TextSegments == null) || (textView.TextSegments.Count == 0)) return false; start = textView.TextSegments[0].Start.CreatePointer(LogicalDirection.Forward); end = textView.TextSegments[textView.TextSegments.Count - 1].End.CreatePointer(LogicalDirection.Backward); Debug.Assert((start != null) && (end != null), "null start/end TextPointer on a non empty page"); return true; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // Name of locator part element private static readonly XmlQualifiedName FixedTextElementName = new XmlQualifiedName("FixedTextRange", AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); // ContentLocatorPart types understood by this processor private static readonly XmlQualifiedName[] LocatorPartTypeNames = new XmlQualifiedName[] { FixedTextElementName }; #endregion Private Fields #region Internal Classes ////// Returned by GetSelectedNodes - one object per page spanned by the selection /// internal sealed class FixedPageProxy : DependencyObject { public FixedPageProxy(DependencyObject parent, int page) { SetValue(PathNode.HiddenParentProperty, parent); _page = page; } public int Page { get { return _page; } } public IListSegments { get { return _segments; } } int _page; IList _segments = new List (1); } /// /// PointSegment represents a segment in fixed content with start and end points. /// internal sealed class PointSegment { ////// Creates a PointSegment with the given points. /// internal PointSegment(Point start, Point end) { _start = start; _end = end; } ////// The start point of the segment /// public Point Start { get { return _start; } } ////// The end point of the segment /// public Point End { get { return _end; } } ////// Used to represent a non-existent point - for instance for a segment /// which spans an entire page there is no starting point. /// public static readonly Point NotAPoint = new Point(double.NaN, double.NaN); private Point _start; private Point _end; } #endregion Internal Classes } } // 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: // FixedTextSelectionProcessor uses TextAnchors to represent portions // of text that are anchors. It produces FixedTextRange locator parts that are designed // specifically for use inside the DocumentViewer control. This locator part contains the // page number and the start and end points of the text selection. // FixedTextSelectionProcessor converts the text selection to FixedTextRange // // Spec: http://team/sites/ag/Specifications/Anchoring%20to%20text%20in%20paginated%20docs.doc // // History: // 09/29/2004: ssimova: Created // 12/07/2004: rruiz: Updated processor to work on new DocumentViewer //----------------------------------------------------------------------------- using System; using System.IO; using System.Windows; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; 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; using MS.Internal.PtsHost; namespace MS.Internal.Annotations.Anchoring { ////// FixedTextSelectionProcessor uses TextAnchors to represent portions /// of text that are anchors. It produces locator parts that /// represent these TextRanges by beginning and end position /// internal class FixedTextSelectionProcessor : SelectionProcessor { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Creates an instance of FixedTextSelectionProcessor. /// public FixedTextSelectionProcessor() { } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Merges the two anchors into one, if possible. It does not require /// the anchors to be connected. All this method does is to create a /// TextAnchor that spans the two anchors. /// /// anchor to merge. Must be a TextAnchor. /// other anchor to merge. Must be a TextAnchor. /// new anchor that contains the data from both /// anchor1 and anchor2 ///true if the anchors were merged, false otherwise /// public override bool MergeSelections(Object anchor1, Object anchor2, out Object newAnchor) { return TextSelectionHelper.MergeSelections(anchor1, anchor2, out newAnchor); } ////// Generates FixedPageProxy objects for each page, spaned by the selection /// /// the selection to examine. Must implement ITextRange ///a list of FixedPageProxy objects, corresponding to each page spanned by the selection; never returns /// null ///selection is null ///selection is of wrong type ///selection start or end point can not be resolved to a page public override IListGetSelectedNodes(Object selection) { IList textSegments = CheckSelection(selection); IList pageEl = new List (); Point start; Point end; foreach (TextSegment segment in textSegments) { int startPage = int.MinValue; ITextPointer startPointer = segment.Start.CreatePointer(LogicalDirection.Forward); TextSelectionHelper.GetPointerPage(startPointer, out startPage); start = TextSelectionHelper.GetPointForPointer(startPointer); if (startPage == int.MinValue) throw new ArgumentException(SR.Get(SRID.SelectionDoesNotResolveToAPage, "start"), "selection"); int endPage = int.MinValue; ITextPointer endPointer = segment.End.CreatePointer(LogicalDirection.Backward); TextSelectionHelper.GetPointerPage(endPointer, out endPage); end = TextSelectionHelper.GetPointForPointer(endPointer); if (endPage == int.MinValue) throw new ArgumentException(SR.Get(SRID.SelectionDoesNotResolveToAPage, "end"), "selection"); int firstPage = pageEl.Count; int numOfPages = endPage - startPage; Debug.Assert(numOfPages >= 0, "start page number is bigger than the end page number"); // If the first page of this segment already has an FPP, then use that one for an additional segment int i = 0; if (pageEl.Count > 0 && ((FixedPageProxy)pageEl[pageEl.Count - 1]).Page == startPage) { firstPage--; // use the existing one from the list as the first i++; // make 1 fewer FPPs } for (; i <= numOfPages; i++) { pageEl.Add(new FixedPageProxy(segment.Start.TextContainer.Parent, startPage + i)); } // If entire segment is on one page set both start/end on that page if (numOfPages == 0) { ((FixedPageProxy)pageEl[firstPage]).Segments.Add(new PointSegment(start, end)); } else { // otherwise set start on the first page and end on the last page ((FixedPageProxy)pageEl[firstPage]).Segments.Add(new PointSegment(start, PointSegment.NotAPoint)); ((FixedPageProxy)pageEl[firstPage + numOfPages]).Segments.Add(new PointSegment(PointSegment.NotAPoint, end)); } } return pageEl; } /// /// Gets the parent element of this selection. The parent element is the /// FixedPage that contains selection.Start TextPointer. /// /// the selection to examine. Must implement ITextRange ///the parent element of the selection; can be null ///selection is null ///selection is of wrong type public override UIElement GetParent(Object selection) { CheckAnchor(selection); return TextSelectionHelper.GetParent(selection); } ////// Gets the anchor point for the selection. This is the Point that corresponds /// to the start position of the selection /// /// the selection to examine. Must implement ITextRange ///the anchor point of the selection; can be (double.NaN, double.NaN) if the /// selection start point is not contained in a document viewer ///selection is null ///selection is of wrong type public override Point GetAnchorPoint(Object selection) { CheckAnchor(selection); return TextSelectionHelper.GetAnchorPoint(selection); } ////// Creates one locator part representing part of the selection /// that lies within start node /// /// the selection that is being processed. Must implement ITextRange /// The FixedPageProxy object, representing one page of the document ///A list containing one FixedTextRange locator part ///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"); CheckSelection(selection); FixedPageProxy fp = startNode as FixedPageProxy; if (fp == null) throw new ArgumentException(SR.Get(SRID.StartNodeMustBeFixedPageProxy), "startNode"); ContentLocatorPart part = new ContentLocatorPart(FixedTextElementName); if (fp.Segments.Count == 0) { part.NameValuePairs.Add(TextSelectionProcessor.CountAttribute, 1.ToString(NumberFormatInfo.InvariantInfo)); part.NameValuePairs.Add(TextSelectionProcessor.SegmentAttribute + 0.ToString(NumberFormatInfo.InvariantInfo), ",,,"); } else { part.NameValuePairs.Add(TextSelectionProcessor.CountAttribute, fp.Segments.Count.ToString(NumberFormatInfo.InvariantInfo)); for (int i = 0; i < fp.Segments.Count; i++) { string value = ""; if (!double.IsNaN(fp.Segments[i].Start.X)) { value += fp.Segments[i].Start.X.ToString(NumberFormatInfo.InvariantInfo) + TextSelectionProcessor.Separator[0] + fp.Segments[i].Start.Y.ToString(NumberFormatInfo.InvariantInfo); } else { value += TextSelectionProcessor.Separator[0]; } value += TextSelectionProcessor.Separator[0]; if (!double.IsNaN(fp.Segments[i].End.X)) { value += fp.Segments[i].End.X.ToString(NumberFormatInfo.InvariantInfo) + TextSelectionProcessor.Separator[0] + fp.Segments[i].End.Y.ToString(NumberFormatInfo.InvariantInfo); } else { value += TextSelectionProcessor.Separator[0]; } part.NameValuePairs.Add(TextSelectionProcessor.SegmentAttribute + i.ToString(NumberFormatInfo.InvariantInfo), value); } } List res = new List (1); res.Add(part); return res; } /// /// Creates a TextRange object spanning the portion of 'startNode' /// specified by 'locatorPart'. /// /// FixedTextRange locator part specifying start and end point of /// the TextRange /// the FixedPage containing this locator part /// set to AttachmentLevel.Full if the FixedPage for the locator /// part was found, AttachmentLevel.Unresolved otherwise ///a TextRange spanning the text between start end end point in the FixedTextRange /// locator part /// , null if selection described by locator part could not be /// recreated ///locatorPart or startNode are /// null ///locatorPart is of the incorrect type ///startNode is not a FixedPage ///startNode does not belong to the DocumentViewer public override Object ResolveLocatorPart(ContentLocatorPart locatorPart, DependencyObject startNode, out AttachmentLevel attachmentLevel) { if (startNode == null) throw new ArgumentNullException("startNode"); DocumentPage docPage = null; FixedPage page = startNode as FixedPage; if (page != null) { docPage = GetDocumentPage(page); } else { // If we were passed a DPV because we are walking the visual tree, // extract the DocumentPage from it; its TextView will be used to // turn coordinates into text positions DocumentPageView dpv = startNode as DocumentPageView; if (dpv != null) { docPage = dpv.DocumentPage as FixedDocumentPage; if (docPage == null) { docPage = dpv.DocumentPage as FixedDocumentSequenceDocumentPage; } } } if (docPage == null) { throw new ArgumentException(SR.Get(SRID.StartNodeMustBeDocumentPageViewOrFixedPage), "startNode"); } if (locatorPart == null) throw new ArgumentNullException("locatorPart"); attachmentLevel = AttachmentLevel.Unresolved; ITextView tv = (ITextView)((IServiceProvider)docPage).GetService(typeof(ITextView)); Debug.Assert(tv != null); ReadOnlyCollectionts = tv.TextSegments; //check first if a TextRange can be generated if (ts == null || ts.Count <= 0) return null; TextAnchor resolvedAnchor = new TextAnchor(); if (docPage != null) { string stringCount = locatorPart.NameValuePairs["Count"]; if (stringCount == null) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.CountAttribute)); int count = Int32.Parse(stringCount, NumberFormatInfo.InvariantInfo); for(int i = 0; i < count; i++) { // First we extract the start and end Point from the locator part. Point start; Point end; GetLocatorPartSegmentValues(locatorPart, i, out start, out end); //calulate start ITextPointer ITextPointer segStart; if (double.IsNaN(start.X) || double.IsNaN(start.Y)) { //get start of the page segStart = FindStartVisibleTextPointer(docPage); } else { //convert Point to TextPointer segStart = tv.GetTextPositionFromPoint(start, true); } if (segStart == null) { //selStart can be null if there are no insertion points on this page continue; } //calulate end ITextPointer ITextPointer segEnd; if (double.IsNaN(end.X) || double.IsNaN(end.Y)) { segEnd = FindEndVisibleTextPointer(docPage); } else { //convert Point to TextPointer segEnd = tv.GetTextPositionFromPoint(end, true); } //end TP can not be null when start is not Invariant.Assert(segEnd != null, "end TP is null when start TP is not"); attachmentLevel = AttachmentLevel.Full; // Not always true right? resolvedAnchor.AddTextSegment(segStart, segEnd); } } if (resolvedAnchor.TextSegments.Count > 0) return resolvedAnchor; else return null; } /// /// 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 // //----------------------------------------------------- //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods private DocumentPage GetDocumentPage(FixedPage page) { Invariant.Assert(page != null); DocumentPage docPage = null; PageContent content = page.Parent as PageContent; if (content != null) { FixedDocument document = content.Parent as FixedDocument; // If the document is part of a FixedDocumentSequence then we want to get the // FixedDocumentSequenceDocumentPage for the FixedPage (cause its TextView is // the one we want to use). FixedDocumentSequence sequence = document.Parent as FixedDocumentSequence; if (sequence != null) { docPage = sequence.GetPage(document, document.GetIndexOfPage(page)); } else { docPage = document.GetPage(document.GetIndexOfPage(page)); } } return docPage; } ////// Checks if the selection object satisfies the requirements /// for this processor /// /// selection ///ITextRange interface, implemented by the object private IListCheckSelection(object selection) { if (selection == null) throw new ArgumentNullException("selection"); IList textSegments = null; ITextPointer start = null; ITextRange textRange = selection as ITextRange; if (textRange != null) { start = textRange.Start; textSegments = textRange.TextSegments; } else { TextAnchor anchor = selection as TextAnchor; if (anchor != null) { start = anchor.Start; textSegments = anchor.TextSegments; } else { throw new ArgumentException(SR.Get(SRID.WrongSelectionType), "selection: type=" + selection.GetType().ToString()); } } if (!(start.TextContainer is FixedTextContainer || start.TextContainer is DocumentSequenceTextContainer)) throw new ArgumentException(SR.Get(SRID.WrongSelectionType), "selection: type=" + selection.GetType().ToString()); return textSegments; } /// /// Checks if the selection object satisfies the requirements /// for this processor /// /// selection ///ITextRange interface, implemented by the object private TextAnchor CheckAnchor(object selection) { if (selection == null) throw new ArgumentNullException("selection"); TextAnchor anchor = selection as TextAnchor; if (anchor == null || !(anchor.Start.TextContainer is FixedTextContainer || anchor.Start.TextContainer is DocumentSequenceTextContainer)) { throw new ArgumentException(SR.Get(SRID.WrongSelectionType), "selection: type=" + selection.GetType().ToString()); } return anchor; } ////// Extracts the values of attributes from a locator part. /// /// the locator part to extract values from /// number of segment value to retrieve /// the start point value based on StartXAttribute and StartYAttribute values /// the end point value based on EndXAttribyte and EndYattribute values private void GetLocatorPartSegmentValues(ContentLocatorPart locatorPart, int segmentNumber, out Point start, out Point end) { if (locatorPart == null) throw new ArgumentNullException("locatorPart"); if (FixedTextElementName != locatorPart.PartType) throw new ArgumentException(SR.Get(SRID.IncorrectLocatorPartType, locatorPart.PartType.Namespace + ":" + locatorPart.PartType.Name), "locatorPart"); string segmentValue = locatorPart.NameValuePairs[TextSelectionProcessor.SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo)]; if (segmentValue == null) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo))); string[] values = segmentValue.Split(TextSelectionProcessor.Separator); if (values.Length != 4) throw new ArgumentException(SR.Get(SRID.InvalidLocatorPart, TextSelectionProcessor.SegmentAttribute + segmentNumber.ToString(NumberFormatInfo.InvariantInfo))); start = GetPoint(values[0], values[1]); end = GetPoint(values[2], values[3]); } ////// Calculate Point out of string X and Y values /// /// x string value /// y string value ///private Point GetPoint(string xstr, string ystr) { Point point; if (xstr != null && !String.IsNullOrEmpty(xstr.Trim()) && ystr != null && !String.IsNullOrEmpty(ystr.Trim())) { double x = Double.Parse(xstr, NumberFormatInfo.InvariantInfo); double y = Double.Parse(ystr, NumberFormatInfo.InvariantInfo); point = new Point(x, y); } else { point = new Point(double.NaN, double.NaN); } return point; } /// /// Gets the first visible TP on a DocumentPage /// /// document page ///The first visible TP or null if no visible TP on this page private static ITextPointer FindStartVisibleTextPointer(DocumentPage documentPage) { ITextPointer start, end; if (!GetTextViewRange(documentPage, out start, out end)) return null; if (!start.IsAtInsertionPosition && !start.MoveToNextInsertionPosition(LogicalDirection.Forward)) { //there is no insertion point in this direction return null; } //check if it is outside of the page if (start.CompareTo(end) > 0) return null; return start; } ////// Gets the last visible TP on a DocumentPage /// /// document page ///The last visible TP or null if no visible TP on the page private static ITextPointer FindEndVisibleTextPointer(DocumentPage documentPage) { ITextPointer start, end; if (!GetTextViewRange(documentPage, out start, out end)) return null; if (!end.IsAtInsertionPosition && !end.MoveToNextInsertionPosition(LogicalDirection.Backward)) { //there is no insertion point in this direction return null; } //check if it is outside of the page if (start.CompareTo(end) > 0) return null; return end; } ////// Gets first and last TP on a documentPage. /// /// the document page /// start TP /// end TP ///true if there aretext segments on this page, otherwise false private static bool GetTextViewRange(DocumentPage documentPage, out ITextPointer start, out ITextPointer end) { ITextView textView; start = end = null; // Missing pages can't produce TextPointers Invariant.Assert(documentPage != DocumentPage.Missing); textView = ((IServiceProvider)documentPage).GetService(typeof(ITextView)) as ITextView; Invariant.Assert(textView != null, "DocumentPage didn't provide a TextView."); //check if there is any content if ((textView.TextSegments == null) || (textView.TextSegments.Count == 0)) return false; start = textView.TextSegments[0].Start.CreatePointer(LogicalDirection.Forward); end = textView.TextSegments[textView.TextSegments.Count - 1].End.CreatePointer(LogicalDirection.Backward); Debug.Assert((start != null) && (end != null), "null start/end TextPointer on a non empty page"); return true; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // Name of locator part element private static readonly XmlQualifiedName FixedTextElementName = new XmlQualifiedName("FixedTextRange", AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); // ContentLocatorPart types understood by this processor private static readonly XmlQualifiedName[] LocatorPartTypeNames = new XmlQualifiedName[] { FixedTextElementName }; #endregion Private Fields #region Internal Classes ////// Returned by GetSelectedNodes - one object per page spanned by the selection /// internal sealed class FixedPageProxy : DependencyObject { public FixedPageProxy(DependencyObject parent, int page) { SetValue(PathNode.HiddenParentProperty, parent); _page = page; } public int Page { get { return _page; } } public IListSegments { get { return _segments; } } int _page; IList _segments = new List (1); } /// /// PointSegment represents a segment in fixed content with start and end points. /// internal sealed class PointSegment { ////// Creates a PointSegment with the given points. /// internal PointSegment(Point start, Point end) { _start = start; _end = end; } ////// The start point of the segment /// public Point Start { get { return _start; } } ////// The end point of the segment /// public Point End { get { return _end; } } ////// Used to represent a non-existent point - for instance for a segment /// which spans an entire page there is no starting point. /// public static readonly Point NotAPoint = new Point(double.NaN, double.NaN); private Point _start; private Point _end; } #endregion Internal Classes } } // 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
- RelatedCurrencyManager.cs
- SafeCryptContextHandle.cs
- SchemaImporterExtensionsSection.cs
- GeneralTransform2DTo3DTo2D.cs
- DirectoryNotFoundException.cs
- backend.cs
- WebPartDeleteVerb.cs
- ListViewInsertEventArgs.cs
- CodeCommentStatementCollection.cs
- TriggerBase.cs
- MenuCommandsChangedEventArgs.cs
- NodeLabelEditEvent.cs
- StoreContentChangedEventArgs.cs
- ContentElement.cs
- ResourceExpression.cs
- Misc.cs
- SamlSecurityToken.cs
- TextDecorations.cs
- Base64Encoding.cs
- AsyncResult.cs
- ComplexBindingPropertiesAttribute.cs
- QilBinary.cs
- BoolExpressionVisitors.cs
- Literal.cs
- TreeViewImageKeyConverter.cs
- ListBoxItemAutomationPeer.cs
- oledbmetadatacollectionnames.cs
- WinFormsComponentEditor.cs
- EnumerationRangeValidationUtil.cs
- SynchronizedDispatch.cs
- VariableAction.cs
- CompoundFileStorageReference.cs
- GeneralTransformGroup.cs
- Int64.cs
- OciHandle.cs
- SHA1CryptoServiceProvider.cs
- PaintEvent.cs
- ValidationHelper.cs
- AssemblyAssociatedContentFileAttribute.cs
- RestHandler.cs
- CharacterHit.cs
- Tracer.cs
- WindowClosedEventArgs.cs
- ReadOnlyState.cs
- SkewTransform.cs
- LinearKeyFrames.cs
- SoapFormatter.cs
- ControlAdapter.cs
- AppDomainShutdownMonitor.cs
- Point3DAnimationBase.cs
- CompatibleComparer.cs
- BaseValidator.cs
- TabPageDesigner.cs
- TriState.cs
- TimeSpan.cs
- DelayedRegex.cs
- RootProfilePropertySettingsCollection.cs
- PrimarySelectionGlyph.cs
- SchemaNamespaceManager.cs
- DoubleAnimationBase.cs
- XmlDocumentSurrogate.cs
- Privilege.cs
- XmlMemberMapping.cs
- Schema.cs
- InvalidComObjectException.cs
- ToolboxItemCollection.cs
- SqlCacheDependencySection.cs
- DocumentEventArgs.cs
- cryptoapiTransform.cs
- Synchronization.cs
- MachineKey.cs
- SecurityChannel.cs
- MailWebEventProvider.cs
- CodeCompileUnit.cs
- SByteStorage.cs
- ConfigXmlSignificantWhitespace.cs
- MimeWriter.cs
- StylusSystemGestureEventArgs.cs
- EntityConnectionStringBuilder.cs
- Point3DKeyFrameCollection.cs
- DocumentApplicationJournalEntry.cs
- WriteTimeStream.cs
- ThicknessAnimation.cs
- SystemDiagnosticsSection.cs
- PolicyFactory.cs
- RefExpr.cs
- ToolBarTray.cs
- WindowsPen.cs
- InputDevice.cs
- Mapping.cs
- MemoryRecordBuffer.cs
- RuntimeIdentifierPropertyAttribute.cs
- ReadOnlyCollection.cs
- DSASignatureFormatter.cs
- DesignerDataColumn.cs
- SqlDataSourceCustomCommandPanel.cs
- NGCPageContentSerializerAsync.cs
- TakeQueryOptionExpression.cs
- EventLogPermissionAttribute.cs
- XPathQueryGenerator.cs