Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / 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: [....]/sites/ag/Specifications/Anchoring%20to%20text%20in%20paginated%20docs.doc
//
// History:
// 09/29/2004: [....]: Created
// 12/07/2004: [....]: 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 IList GetSelectedNodes(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 IList
GenerateLocatorParts(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);
ReadOnlyCollection ts = 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 IList CheckSelection(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 IList Segments
{
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
- ProfileService.cs
- HTTPAPI_VERSION.cs
- DataBindingCollection.cs
- SimpleType.cs
- EntityProviderFactory.cs
- AppSettingsExpressionBuilder.cs
- LinkLabel.cs
- PropertyInformationCollection.cs
- ResourcePool.cs
- MenuItemBindingCollection.cs
- securestring.cs
- Popup.cs
- Propagator.cs
- OdbcConnectionStringbuilder.cs
- RequestCacheValidator.cs
- TargetControlTypeCache.cs
- HttpListener.cs
- DaylightTime.cs
- RowType.cs
- Tuple.cs
- behaviorssection.cs
- UTF8Encoding.cs
- IndicShape.cs
- BaseResourcesBuildProvider.cs
- RegexMatch.cs
- PropertyChangeTracker.cs
- WriteTimeStream.cs
- StylusCaptureWithinProperty.cs
- DeclarativeCatalogPart.cs
- Section.cs
- DataListCommandEventArgs.cs
- UIElementIsland.cs
- Model3DGroup.cs
- SingleTagSectionHandler.cs
- ActionFrame.cs
- XmlIlVisitor.cs
- WebBrowserBase.cs
- TraceLevelStore.cs
- JpegBitmapDecoder.cs
- SiteOfOriginPart.cs
- FontResourceCache.cs
- basenumberconverter.cs
- OutputCache.cs
- SimpleLine.cs
- recordstatefactory.cs
- ClientType.cs
- ArgumentException.cs
- MemberPath.cs
- FlowDocumentFormatter.cs
- CodeDirectoryCompiler.cs
- AttributeCollection.cs
- CharStorage.cs
- PropertyTab.cs
- MulticastOption.cs
- SplitterCancelEvent.cs
- SortAction.cs
- XmlAnyElementAttribute.cs
- CqlIdentifiers.cs
- ConnectionManagementElement.cs
- CompareValidator.cs
- PropertyMetadata.cs
- FindCriteria.cs
- Int32.cs
- ImageIndexConverter.cs
- SyndicationElementExtension.cs
- MetadataPropertyCollection.cs
- SynchronizedDispatch.cs
- Camera.cs
- UnicastIPAddressInformationCollection.cs
- AsyncPostBackErrorEventArgs.cs
- FilterElement.cs
- AddInServer.cs
- DataTableNewRowEvent.cs
- Pkcs9Attribute.cs
- Size3DConverter.cs
- PointF.cs
- ProfilePropertySettingsCollection.cs
- TypedDataSourceCodeGenerator.cs
- TriggerAction.cs
- TextRunCache.cs
- DesignerSelectionListAdapter.cs
- EpmContentDeSerializerBase.cs
- ViewPort3D.cs
- IssuedSecurityTokenParameters.cs
- ProfilePropertySettings.cs
- CodeSnippetExpression.cs
- UpdateCommand.cs
- DataGridViewColumnEventArgs.cs
- NameScope.cs
- VisualTreeHelper.cs
- BamlResourceSerializer.cs
- ErrorWebPart.cs
- XmlSchemaDatatype.cs
- DataGridPreparingCellForEditEventArgs.cs
- CommandExpr.cs
- CodeNamespaceImport.cs
- AccessDataSourceView.cs
- InterleavedZipPartStream.cs
- ContainerActivationHelper.cs
- ResourceManager.cs