//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region InternalMethods /// <summary> /// Creates the dot product of this ContentLocator and the list of /// ContentLocatorParts. The result is n Locators where n is the number of /// ContentLocatorParts passed in. /// One of the resulting Locators is this ContentLocator. If there are no /// additional ContentLocatorParts a list with just this ContentLocator (unmodified) /// is returned. /// </summary> /// <param name="additionalLocatorParts">array of ContentLocatorParts</param> /// <returns>array of Locators (one for each additional ContentLocatorPart)</returns> internal IList <ContentLocatorBase> DotProduct(IList <ContentLocatorPart> additionalLocatorParts) { List <ContentLocatorBase> results = null; // If there aren't any additional locator parts - this is basically a no-op if (additionalLocatorParts == null || additionalLocatorParts.Count == 0) { results = new List <ContentLocatorBase>(1); results.Add(this); } else { results = new List <ContentLocatorBase>(additionalLocatorParts.Count); for (int i = 1; i < additionalLocatorParts.Count; i++) { ContentLocator loc = (ContentLocator)this.Clone(); loc.Parts.Add(additionalLocatorParts[i]); results.Add(loc); } this.Parts.Add(additionalLocatorParts[0]); results.Insert(0, this); } return(results); }
/// <summary> /// Reads the internal data for this ContentLocatorGroup from the reader. This method /// is used by an XmlSerializer to deserialize a ContentLocatorGroup. To deserialize a /// ContentLocatorGroup from Xml, use an XmlSerializer. /// </summary> /// <param name="reader">the reader to read internal data from</param> /// <exception cref="ArgumentNullException">reader is null</exception> public void ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } // We expect no attributes on a "ContentLocatorGroup", // so throw using the name of one of the unexpected attributes Annotation.CheckForNonNamespaceAttribute(reader, AnnotationXmlConstants.Elements.ContentLocatorGroup); if (!reader.IsEmptyElement) { reader.Read(); // Reads the start of the "ContentLocatorGroup" element // Consume everything inside of the ContentLocatorGroup tag. while (!(AnnotationXmlConstants.Elements.ContentLocatorGroup == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { // If a child node is a <ContentLocatorBase>, deserialize a ContentLocatorBase if (AnnotationXmlConstants.Elements.ContentLocator == reader.LocalName) { ContentLocator locator = (ContentLocator)AnnotationResource.ListSerializer.Deserialize(reader); _locators.Add(locator); } else { // The ContentLocatorGroup contains a child that is not a ContentLocatorBase or // text. This isn't valid in the schema so we throw. throw new XmlException(SR.Get(SRID.InvalidXmlContent, AnnotationXmlConstants.Elements.ContentLocatorGroup)); } } } reader.Read(); // Reads the end of the "ContentLocatorGroup" element (or whole element if empty) }
/// <summary>Returns a value that indicates whether the starting sequence of <see cref="T:System.Windows.Annotations.ContentLocatorPart" /> elements in a specified <see cref="T:System.Windows.Annotations.ContentLocator" /> are identical to those in this <see cref="T:System.Windows.Annotations.ContentLocator" />.</summary> /// <param name="locator">The <see cref="T:System.Windows.Annotations.ContentLocator" /> with the list of <see cref="T:System.Windows.Annotations.ContentLocatorPart" /> elements to compare with this <see cref="T:System.Windows.Annotations.ContentLocator" />.</param> /// <returns> /// <see langword="true" /> if the starting sequence of <see cref="T:System.Windows.Annotations.ContentLocatorPart" /> elements in this <see cref="T:System.Windows.Annotations.ContentLocator" /> matches those in the specified <paramref name="locator" />; otherwise, <see langword="false" />.</returns> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="locator" /> is <see langword="null" />.</exception> // Token: 0x06006337 RID: 25399 RVA: 0x001BE4EC File Offset: 0x001BC6EC public bool StartsWith(ContentLocator locator) { if (locator == null) { throw new ArgumentNullException("locator"); } Invariant.Assert(locator.Parts != null, "Locator has null Parts property."); if (this.Parts.Count < locator.Parts.Count) { return(false); } for (int i = 0; i < locator.Parts.Count; i++) { ContentLocatorPart contentLocatorPart = locator.Parts[i]; ContentLocatorPart contentLocatorPart2 = this.Parts[i]; if (contentLocatorPart == null && contentLocatorPart2 != null) { return(false); } if (!contentLocatorPart.Matches(contentLocatorPart2)) { return(false); } } return(true); }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Determines if this list begins with the ContentLocatorParts that /// make up matchList. All ContentLocatorParts in matchList must /// be present and in the same order in this list for /// true to be returned. /// </summary> /// <param name="locator">the list to compare with</param> /// <returns> /// true if this list begins with the ContentLocatorParts in locator; /// false otherwise. If locator is longer than this locator, will /// return false as well. /// </returns> /// <exception cref="ArgumentNullException">locator is null</exception> public bool StartsWith(ContentLocator locator) { if (locator == null) { throw new ArgumentNullException("locator"); } Invariant.Assert(locator.Parts != null, "Locator has null Parts property."); // If this locator is shorter than matchList, then this can't contain matchList. #pragma warning suppress 6506 // Invariant.Assert(locator.Parts != null) if (this.Parts.Count < locator.Parts.Count) { return(false); } for (int locatorPartIndex = 0; locatorPartIndex < locator.Parts.Count; locatorPartIndex++) { ContentLocatorPart left = locator.Parts[locatorPartIndex]; ContentLocatorPart right = this.Parts[locatorPartIndex]; // ContentLocator parts can be null so check for that case here if (left == null && right != null) { return(false); } if (!left.Matches(right)) { return(false); } } return(true); }
// Token: 0x060062D4 RID: 25300 RVA: 0x001BBA20 File Offset: 0x001B9C20 private static IList <IAttachedAnnotation> GetSpannedAnnotationsForFixed(AnnotationService service, int startPage, int endPage) { Invariant.Assert(service != null, "Need non-null service to get spanned annotations for fixed content."); FixedPageProcessor fixedPageProcessor = service.LocatorManager.GetSubTreeProcessorForLocatorPart(FixedPageProcessor.CreateLocatorPart(0)) as FixedPageProcessor; Invariant.Assert(fixedPageProcessor != null, "FixedPageProcessor should be available if we are processing fixed content."); List <IAttachedAnnotation> result = null; List <Annotation> annotations = new List <Annotation>(); try { fixedPageProcessor.UseLogicalTree = true; for (int i = startPage; i <= endPage; i++) { ContentLocator contentLocator = new ContentLocator(); contentLocator.Parts.Add(FixedPageProcessor.CreateLocatorPart(i)); AnnotationHelper.AddRange(annotations, service.Store.GetAnnotations(contentLocator)); } result = AnnotationHelper.ResolveAnnotations(service, annotations); } finally { fixedPageProcessor.UseLogicalTree = false; } return(result); }
/// <summary>Deserializes the <see cref="T:System.Windows.Annotations.ContentLocatorGroup" /> from a specified <see cref="T:System.Xml.XmlReader" />.</summary> /// <param name="reader">The XML reader to use to deserialize the <see cref="T:System.Windows.Annotations.ContentLocatorGroup" />.</param> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="reader" /> is <see langword="null" />.</exception> /// <exception cref="T:System.Xml.XmlException">The serialized XML for the <see cref="T:System.Windows.Annotations.ContentLocatorGroup" /> is not valid.</exception> // Token: 0x06006345 RID: 25413 RVA: 0x001BECA4 File Offset: 0x001BCEA4 public void ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } Annotation.CheckForNonNamespaceAttribute(reader, "ContentLocatorGroup"); if (!reader.IsEmptyElement) { reader.Read(); while (!("ContentLocatorGroup" == reader.LocalName) || XmlNodeType.EndElement != reader.NodeType) { if (!("ContentLocator" == reader.LocalName)) { throw new XmlException(SR.Get("InvalidXmlContent", new object[] { "ContentLocatorGroup" })); } ContentLocator item = (ContentLocator)AnnotationResource.ListSerializer.Deserialize(reader); this._locators.Add(item); } } reader.Read(); }
// Token: 0x0600633F RID: 25407 RVA: 0x001BEB14 File Offset: 0x001BCD14 internal void Append(ContentLocator other) { Invariant.Assert(other != null, "Parameter 'other' is null."); foreach (ContentLocatorPart contentLocatorPart in other.Parts) { this.Parts.Add((ContentLocatorPart)contentLocatorPart.Clone()); } }
/// <summary> /// Merges this ContentLocator with a ContentLocatorBase. If other is a /// ContentLocatorGroup, each of its Locators are added to clones of /// this ContentLocatorBase and are added to a new ContentLocatorGroup which is /// returned. If other is a ContentLocatorBase, its appended to this /// ContentLocatorBase and this ContentLocatorBase is returned. /// Both operation modify this ContentLocatorBase. /// </summary> /// <param name="other">the ContentLocatorBase to merge with</param> /// <returns>a ContentLocatorBase containing the final merged product</returns> internal override ContentLocatorBase Merge(ContentLocatorBase other) { if (other == null) { return(this); } ContentLocatorGroup locatorGroup = other as ContentLocatorGroup; if (locatorGroup != null) { ContentLocatorGroup newGroup = new ContentLocatorGroup(); ContentLocator temp = null; // Create n-1 clones of this LPS and append all but one // LPSs in the set to the clones, adding the clones to a // new ContentLocatorGroup foreach (ContentLocator loc in locatorGroup.Locators) { if (temp == null) { temp = loc; } else { ContentLocator clone = (ContentLocator)this.Clone(); clone.Append(loc); newGroup.Locators.Add(clone); } } // Finally, add the remaining LPS in the set to this LPS // and add this to the new ContentLocatorGroup if (temp != null) { this.Append(temp); newGroup.Locators.Add(this); } if (newGroup.Locators.Count == 0) { return(this); } else { return(newGroup); } } else { // Safe cast - ContentLocator only has two subclasses this.Append((ContentLocator)other); return(this); } }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// <summary> /// Merges the ContentLocatorGroup with a ContentLocatorBase. If other is a ContentLocatorBase, /// it is added to the end of every ContentLocatorBase in this ContentLocatorGroup. /// If other is a ContentLocatorGroup, then each ContentLocatorBase in it must be added to /// each ContentLocatorBase (or a clone) in this ContentLocatorGroup. The result is this /// ContentLocatorGroup will contain n*m ContentLocatorBase. /// In both cases, this ContentLocatorGroup is modified. /// </summary> /// <param name="other">other ContentLocatorBase to merge with</param> /// <returns>this ContentLocatorGroup</returns> internal override ContentLocatorBase Merge(ContentLocatorBase other) { if (other == null) { return(this); } ContentLocator firstRight = null; ContentLocatorGroup locatorGroup = other as ContentLocatorGroup; if (locatorGroup != null) { List <ContentLocatorBase> tempList = new List <ContentLocatorBase>(locatorGroup.Locators.Count * (this.Locators.Count - 1)); foreach (ContentLocator left in this.Locators) { foreach (ContentLocator right in locatorGroup.Locators) { if (firstRight == null) { firstRight = right; } else { ContentLocator clone = (ContentLocator)left.Clone(); clone.Append(right); tempList.Add(clone); } } // No need to clone or add here - just use the locator // already in the ContentLocatorGroup left.Append(firstRight); firstRight = null; } foreach (ContentLocator list in tempList) { this.Locators.Add(list); } } else { ContentLocator otherLoc = other as ContentLocator; Invariant.Assert(otherLoc != null, "other should be of type ContentLocator"); // Only other possible type for the ContentLocatorBase foreach (ContentLocator loc in this.Locators) { loc.Append(otherLoc); } } return(this); }
private IList <IAttachedAnnotation> ProcessAnnotations(DocumentPageView dpv) { if (dpv == null) { throw new ArgumentNullException("dpv"); } IList <IAttachedAnnotation> attachedAnnotations = new List <IAttachedAnnotation>(); IList <ContentLocatorBase> locators = _locatorManager.GenerateLocators(dpv); if (locators.Count > 0) { // LocatorBases for a single node should always be Locators ContentLocator[] lists = new ContentLocator[locators.Count]; locators.CopyTo(lists, 0); IList <Annotation> annotations = _annotationStore.GetAnnotations(lists[0]); foreach (ContentLocator locator in locators) { if (locator.Parts[locator.Parts.Count - 1].NameValuePairs.ContainsKey(TextSelectionProcessor.IncludeOverlaps)) { locator.Parts.RemoveAt(locator.Parts.Count - 1); } } foreach (Annotation annotation in annotations) { foreach (AnnotationResource anchor in annotation.Anchors) { foreach (ContentLocatorBase locator in anchor.ContentLocators) { AttachmentLevel attachmentLevel; object attachedAnchor = _locatorManager.FindAttachedAnchor(dpv, lists, locator, out attachmentLevel); if (attachmentLevel != AttachmentLevel.Unresolved) { Invariant.Assert(VisualTreeHelper.GetChildrenCount(dpv) == 1, "DocumentPageView has no visual children."); DependencyObject firstElement = VisualTreeHelper.GetChild(dpv, 0); attachedAnnotations.Add(new AttachedAnnotation(_locatorManager, annotation, anchor, attachedAnchor, attachmentLevel, firstElement as DocumentPageHost)); // Only process one locator per resource break; } } } } } return(attachedAnnotations); }
// Token: 0x06006347 RID: 25415 RVA: 0x001BED58 File Offset: 0x001BCF58 internal override ContentLocatorBase Merge(ContentLocatorBase other) { if (other == null) { return(this); } ContentLocator contentLocator = null; ContentLocatorGroup contentLocatorGroup = other as ContentLocatorGroup; if (contentLocatorGroup != null) { List <ContentLocatorBase> list = new List <ContentLocatorBase>(contentLocatorGroup.Locators.Count * (this.Locators.Count - 1)); foreach (ContentLocator contentLocator2 in this.Locators) { foreach (ContentLocator contentLocator3 in contentLocatorGroup.Locators) { if (contentLocator == null) { contentLocator = contentLocator3; } else { ContentLocator contentLocator4 = (ContentLocator)contentLocator2.Clone(); contentLocator4.Append(contentLocator3); list.Add(contentLocator4); } } contentLocator2.Append(contentLocator); contentLocator = null; } using (List <ContentLocatorBase> .Enumerator enumerator3 = list.GetEnumerator()) { while (enumerator3.MoveNext()) { ContentLocatorBase contentLocatorBase = enumerator3.Current; ContentLocator item = (ContentLocator)contentLocatorBase; this.Locators.Add(item); } return(this); } } ContentLocator contentLocator5 = other as ContentLocator; Invariant.Assert(contentLocator5 != null, "other should be of type ContentLocator"); foreach (ContentLocator contentLocator6 in this.Locators) { contentLocator6.Append(contentLocator5); } return(this); }
// Token: 0x0600629B RID: 25243 RVA: 0x001BAA28 File Offset: 0x001B8C28 private IList <IAttachedAnnotation> ProcessAnnotations(DocumentPageView dpv) { if (dpv == null) { throw new ArgumentNullException("dpv"); } IList <IAttachedAnnotation> list = new List <IAttachedAnnotation>(); IList <ContentLocatorBase> list2 = this._locatorManager.GenerateLocators(dpv); if (list2.Count > 0) { ContentLocator[] array = new ContentLocator[list2.Count]; list2.CopyTo(array, 0); IList <Annotation> annotations = this._annotationStore.GetAnnotations(array[0]); foreach (ContentLocatorBase contentLocatorBase in list2) { ContentLocator contentLocator = (ContentLocator)contentLocatorBase; if (contentLocator.Parts[contentLocator.Parts.Count - 1].NameValuePairs.ContainsKey("IncludeOverlaps")) { contentLocator.Parts.RemoveAt(contentLocator.Parts.Count - 1); } } foreach (Annotation annotation in annotations) { foreach (AnnotationResource annotationResource in annotation.Anchors) { foreach (ContentLocatorBase locator in annotationResource.ContentLocators) { AttachmentLevel attachmentLevel; object attachedAnchor = this._locatorManager.FindAttachedAnchor(dpv, array, locator, out attachmentLevel); if (attachmentLevel != AttachmentLevel.Unresolved) { Invariant.Assert(VisualTreeHelper.GetChildrenCount(dpv) == 1, "DocumentPageView has no visual children."); DependencyObject child = VisualTreeHelper.GetChild(dpv, 0); list.Add(new AttachedAnnotation(this._locatorManager, annotation, annotationResource, attachedAnchor, attachmentLevel, child as DocumentPageHost)); break; } } } } } return(list); }
/// <summary>Creates a modifiable deep copy clone of this <see cref="T:System.Windows.Annotations.ContentLocator" />.</summary> /// <returns>A modifiable deep copy clone of this <see cref="T:System.Windows.Annotations.ContentLocator" />.</returns> // Token: 0x06006338 RID: 25400 RVA: 0x001BE578 File Offset: 0x001BC778 public override object Clone() { ContentLocator contentLocator = new ContentLocator(); foreach (ContentLocatorPart contentLocatorPart in this.Parts) { ContentLocatorPart item; if (contentLocatorPart != null) { item = (ContentLocatorPart)contentLocatorPart.Clone(); } else { item = null; } contentLocator.Parts.Add(item); } return(contentLocator); }
/// <summary> /// Creates a deep copy of this list. A new list with a clone of /// every ContentLocatorPart in this list, in the same order, is returned. /// Never returns null. /// </summary> /// <returns>a deep copy of this list</returns> public override Object Clone() { ContentLocator clone = new ContentLocator(); ContentLocatorPart newPart = null; foreach (ContentLocatorPart part in this.Parts) { if (part != null) { newPart = (ContentLocatorPart)part.Clone(); } else { newPart = null; } clone.Parts.Add(newPart); } return(clone); }
// Token: 0x0600633E RID: 25406 RVA: 0x001BEA54 File Offset: 0x001BCC54 internal override ContentLocatorBase Merge(ContentLocatorBase other) { if (other == null) { return(this); } ContentLocatorGroup contentLocatorGroup = other as ContentLocatorGroup; if (contentLocatorGroup == null) { this.Append((ContentLocator)other); return(this); } ContentLocatorGroup contentLocatorGroup2 = new ContentLocatorGroup(); ContentLocator contentLocator = null; foreach (ContentLocator contentLocator2 in contentLocatorGroup.Locators) { if (contentLocator == null) { contentLocator = contentLocator2; } else { ContentLocator contentLocator3 = (ContentLocator)this.Clone(); contentLocator3.Append(contentLocator2); contentLocatorGroup2.Locators.Add(contentLocator3); } } if (contentLocator != null) { this.Append(contentLocator); contentLocatorGroup2.Locators.Add(this); } if (contentLocatorGroup2.Locators.Count == 0) { return(this); } return(contentLocatorGroup2); }
// Token: 0x0600633D RID: 25405 RVA: 0x001BE9CC File Offset: 0x001BCBCC internal IList <ContentLocatorBase> DotProduct(IList <ContentLocatorPart> additionalLocatorParts) { List <ContentLocatorBase> list; if (additionalLocatorParts == null || additionalLocatorParts.Count == 0) { list = new List <ContentLocatorBase>(1); list.Add(this); } else { list = new List <ContentLocatorBase>(additionalLocatorParts.Count); for (int i = 1; i < additionalLocatorParts.Count; i++) { ContentLocator contentLocator = (ContentLocator)this.Clone(); contentLocator.Parts.Add(additionalLocatorParts[i]); list.Add(contentLocator); } this.Parts.Add(additionalLocatorParts[0]); list.Insert(0, this); } return(list); }
// Token: 0x060062D3 RID: 25299 RVA: 0x001BB8C4 File Offset: 0x001B9AC4 private static IList <IAttachedAnnotation> GetSpannedAnnotationsForFlow(AnnotationService service, ITextSelection selection) { Invariant.Assert(service != null); ITextPointer textPointer = selection.Start.CreatePointer(); ITextPointer textPointer2 = selection.End.CreatePointer(); textPointer.MoveToNextInsertionPosition(LogicalDirection.Backward); textPointer2.MoveToNextInsertionPosition(LogicalDirection.Forward); ITextRange selection2 = new TextRange(textPointer, textPointer2); IList <ContentLocatorBase> list = service.LocatorManager.GenerateLocators(selection2); Invariant.Assert(list != null && list.Count > 0); TextSelectionProcessor textSelectionProcessor = service.LocatorManager.GetSelectionProcessor(typeof(TextRange)) as TextSelectionProcessor; TextSelectionProcessor textSelectionProcessor2 = service.LocatorManager.GetSelectionProcessor(typeof(TextAnchor)) as TextSelectionProcessor; Invariant.Assert(textSelectionProcessor != null, "TextSelectionProcessor should be available for TextRange if we are processing flow content."); Invariant.Assert(textSelectionProcessor2 != null, "TextSelectionProcessor should be available for TextAnchor if we are processing flow content."); IList <IAttachedAnnotation> result = null; try { textSelectionProcessor.Clamping = false; textSelectionProcessor2.Clamping = false; ContentLocator contentLocator = list[0] as ContentLocator; Invariant.Assert(contentLocator != null, "Locators for selection in Flow should always be ContentLocators. ContentLocatorSets not supported."); contentLocator.Parts[contentLocator.Parts.Count - 1].NameValuePairs.Add("IncludeOverlaps", bool.TrueString); IList <Annotation> annotations = service.Store.GetAnnotations(contentLocator); result = AnnotationHelper.ResolveAnnotations(service, annotations); } finally { textSelectionProcessor.Clamping = true; textSelectionProcessor2.Clamping = true; } return(result); }
/// <summary> /// Determines if the locator matches any of the prefixes, and if so, returns /// the length of the prefix that was matched. Resolving of the locator can /// begin with the first locator part after those that were matched by the prefix. /// </summary> /// <param name="prefixes">locators representing prefixes to match</param> /// <param name="locator">locator to find a match for</param> /// <param name="matched">whether or not a match was found</param> /// <returns>index of the next locator part to resolve</returns> private int FindMatchingPrefix(ContentLocator[] prefixes, ContentLocatorBase locator, out bool matched) { matched = true; int locatorPartIdx = 0; ContentLocator realLocator = locator as ContentLocator; // If we have a locator set or there are no prefixes then we // are 'matched' implicitly. if (realLocator != null && prefixes != null && prefixes.Length > 0) { matched = false; foreach (ContentLocator prefix in prefixes) { if (realLocator.StartsWith(prefix)) { locatorPartIdx = prefix.Parts.Count; matched = true; break; } } } return locatorPartIdx; }
/// <summary> /// Searches the element subtree for a node that maps to the /// passed in ContentLocatorBase. /// Note: For LocatorGroups the startNode, offset, and prefixes /// are ignored. Due to the nature of LocatorGroups, we always /// start searching at the node with the service enabled, with /// the first locator part, ignoring all prefixes. /// </summary> /// <param name="startNode">the root of the subtree to search</param> /// <param name="prefixes">locators for the root of the subtree</param> /// <param name="locator">the ContentLocatorBase we are resolving to an anchor</param> /// <param name="attachmentLevel">type of the anchor returned</param> /// <returns>the anchor for the passed in ContentLocatorBase; will return null if no match can be found</returns> /// <exception cref="ArgumentNullException">startNode or locator is null</exception> internal Object FindAttachedAnchor(DependencyObject startNode, ContentLocator[] prefixes, ContentLocatorBase locator, out AttachmentLevel attachmentLevel) { if (startNode == null) throw new ArgumentNullException("startNode"); if (locator == null) throw new ArgumentNullException("locator"); // Set it to unresolved initially attachmentLevel = AttachmentLevel.Unresolved; Object anchor = null; bool matched = true; int locatorPartIdx = FindMatchingPrefix(prefixes, locator, out matched); // The annotation's locator starts with at least // one of the locators for the local root. if (matched) { ContentLocator realLocator = locator as ContentLocator; if (realLocator == null || locatorPartIdx < realLocator.Parts.Count) { // Now we try to resolve. If any locator parts were matched to the startNode we want to // start resolving with its children, skipping a revisit to the startNode. anchor = InternalResolveLocator(locator, locatorPartIdx, startNode, locatorPartIdx != 0 /*skipStartNode*/, out attachmentLevel); } // If nothing was returned, we base our return values on the results // of matching against the local root. if (attachmentLevel == AttachmentLevel.Unresolved && locatorPartIdx > 0) { if (locatorPartIdx == 0) { attachmentLevel = AttachmentLevel.Unresolved; } // If there was anything left to resolve then its incomplete // else if (realLocator != null && locatorPartIdx < realLocator.Parts.Count) { attachmentLevel = AttachmentLevel.Incomplete; anchor = startNode; } // otherwise its fully resolved else { attachmentLevel = AttachmentLevel.Full; anchor = startNode; } } } return anchor; }
/// <summary> /// Called by processors when they've encountered content in the tree /// that should have annotations processed for it. This is a low-level /// method that will get called several times during the algorithm for /// loading annotations. /// </summary> /// <param name="node">the tree node that needs to be processed</param> /// <returns>list of IAttachedAnnotations that were loaded for 'node'; /// the list will never be null but may be empty</returns> /// <exception cref="ArgumentNullException">node is null</exception> /// <exception cref="SystemException">no AnnotationStore is available from /// the element tree</exception> public IList<IAttachedAnnotation> ProcessAnnotations(DependencyObject node) { VerifyAccess(); if (node == null) throw new ArgumentNullException("node"); IList<IAttachedAnnotation> attachedAnnotations = new List<IAttachedAnnotation>(); IList<ContentLocatorBase> locators = GenerateLocators(node); if(locators.Count > 0) { AnnotationStore store = null; if (_internalStore != null) { store = _internalStore; } else { AnnotationService service = AnnotationService.GetService(node); if (service == null || !service.IsEnabled) { throw new InvalidOperationException(SR.Get(SRID.AnnotationServiceNotEnabled)); } store = service.Store; } // LocatorBases for a single node should always be Locators ContentLocator[] lists = new ContentLocator[locators.Count]; locators.CopyTo(lists, 0); IList<Annotation> annotations = store.GetAnnotations(lists[0]); foreach (ContentLocator locator in locators) { if (locator.Parts[locator.Parts.Count - 1].NameValuePairs.ContainsKey(TextSelectionProcessor.IncludeOverlaps)) { locator.Parts.RemoveAt(locator.Parts.Count - 1); } } foreach (Annotation annotation in annotations) { foreach (AnnotationResource anchor in annotation.Anchors) { foreach(ContentLocatorBase locator in anchor.ContentLocators) { AttachmentLevel attachmentLevel; object attachedAnchor = FindAttachedAnchor(node, lists, locator, out attachmentLevel); if(attachmentLevel != AttachmentLevel.Unresolved) { Debug.Assert(attachedAnchor != null, "AttachedAnchor cannot be null if attachmentLevel is not Unresolved."); attachedAnnotations.Add(new AttachedAnnotation(this, annotation, anchor, attachedAnchor, attachmentLevel)); // Only process one locator per resource break; } } } } } return attachedAnnotations; }
/// <summary> /// Resolves a single locator starting at the given startNode. /// Sets the selection and attachmentLevel if necessary. /// </summary> /// <param name="selection">object representing the content that has been resolved /// so far; updated if the locator passed in is resolved</param> /// <param name="attachmentLevel">attachmentLevel of content that has been resolved /// so far; updated based on the resolution of the passed in locator</param> /// <param name="attemptedLevel">the level that is represented by this locator - /// start, middle or end</param> /// <param name="locator">the locator to resolve</param> /// <param name="offset">the offset into the locator to start the resolution at</param> /// <param name="startNode">the node to start the resolution at</param> /// <param name="skipStartNode">whether or not the start node should be looked at</param> /// <returns>the data representing the resolution of the single locator; used for /// special cases by calling code to override results from this method</returns> private ResolvingLocatorState ResolveSingleLocator(ref object selection, ref AttachmentLevel attachmentLevel, AttachmentLevel attemptedLevel, ContentLocator locator, int offset, DependencyObject startNode, bool skipStartNode) { ResolvingLocatorState data = new ResolvingLocatorState(); data.LocatorPartIndex = offset; data.ContentLocatorBase = locator; PrePostDescendentsWalker<ResolvingLocatorState> walker = new PrePostDescendentsWalker<ResolvingLocatorState>(TreeWalkPriority.VisualTree, ResolveLocatorPart, TerminateResolve, data); walker.StartWalk(startNode, skipStartNode); if (data.AttachmentLevel == AttachmentLevel.Full && data.AttachedAnchor != null) { // Merge the results with pre-existing selection if (selection != null) { SelectionProcessor selProcessor = GetSelectionProcessor(selection.GetType()); object newSelection; if (selProcessor != null) { if (selProcessor.MergeSelections(selection, data.AttachedAnchor, out newSelection)) { selection = newSelection; } else { // If we can't merge, them this locator isn't included in final results so we // we turn off the level that we are attempting to resolve attachmentLevel &= ~attemptedLevel; } } else { // If not selection processor, the locator can't be resolved so // we turn off the level that we were attempting to resolve attachmentLevel &= ~attemptedLevel; } } else { selection = data.AttachedAnchor; } } else { // ContentLocator didn't fully resolve so we turn off the level // that we were attempting to resolve attachmentLevel &= ~attemptedLevel; } return data; }
/// <summary> /// Creates a deep copy of this list. A new list with a clone of /// every ContentLocatorPart in this list, in the same order, is returned. /// Never returns null. /// </summary> /// <returns>a deep copy of this list</returns> public override Object Clone() { ContentLocator clone = new ContentLocator(); ContentLocatorPart newPart = null; foreach (ContentLocatorPart part in this.Parts) { if (part != null) newPart = (ContentLocatorPart)part.Clone(); else newPart = null; clone.Parts.Add(newPart); } return clone; }
/// <summary> /// Appends a ContentLocator to this ContentLocator. The passed in /// ContentLocator is not modified in anyway. Its ContentLocatorParts are cloned. /// </summary> /// <param name="other">locator to append</param> internal void Append(ContentLocator other) { Invariant.Assert(other != null, "Parameter 'other' is null."); foreach(ContentLocatorPart part in other.Parts) { this.Parts.Add((ContentLocatorPart)part.Clone()); } }
private IList<IAttachedAnnotation> ProcessAnnotations(DocumentPageView dpv) { if (dpv == null) throw new ArgumentNullException("dpv"); IList<IAttachedAnnotation> attachedAnnotations = new List<IAttachedAnnotation>(); IList<ContentLocatorBase> locators = _locatorManager.GenerateLocators(dpv); if (locators.Count > 0) { // LocatorBases for a single node should always be Locators ContentLocator[] lists = new ContentLocator[locators.Count]; locators.CopyTo(lists, 0); IList<Annotation> annotations = _annotationStore.GetAnnotations(lists[0]); foreach (ContentLocator locator in locators) { if (locator.Parts[locator.Parts.Count - 1].NameValuePairs.ContainsKey(TextSelectionProcessor.IncludeOverlaps)) { locator.Parts.RemoveAt(locator.Parts.Count - 1); } } foreach (Annotation annotation in annotations) { foreach (AnnotationResource anchor in annotation.Anchors) { foreach (ContentLocatorBase locator in anchor.ContentLocators) { AttachmentLevel attachmentLevel; object attachedAnchor = _locatorManager.FindAttachedAnchor(dpv, lists, locator, out attachmentLevel); if (attachmentLevel != AttachmentLevel.Unresolved) { Invariant.Assert(VisualTreeHelper.GetChildrenCount(dpv) == 1, "DocumentPageView has no visual children."); DependencyObject firstElement = VisualTreeHelper.GetChild(dpv, 0); attachedAnnotations.Add(new AttachedAnnotation(_locatorManager, annotation, anchor, attachedAnchor, attachmentLevel, firstElement as DocumentPageHost)); // Only process one locator per resource break; } } } } } return attachedAnnotations; }
/// <summary> /// Queries the store map for annotations that have an anchor /// that contains a locator that begins with the locator parts /// in anchorLocator. /// </summary> /// <param name="anchorLocator">the locator we are looking for</param> /// <returns> /// A list of annotations that have locators in their anchors /// starting with the same locator parts list as of the input locator /// If no such annotations an empty list will be returned. The method /// never returns null. /// </returns> public Dictionary<Guid, Annotation> FindAnnotations(ContentLocator anchorLocator) { if (anchorLocator == null) throw new ArgumentNullException("locator"); Dictionary<Guid, Annotation> annotations = new Dictionary<Guid, Annotation>(); // Dictionary<Guid, CachedAnnotation>.ValueCollection.Enumerator annotationsEnumerator = _currentAnnotations.Values.GetEnumerator(); while (annotationsEnumerator.MoveNext()) { Annotation annotation = annotationsEnumerator.Current.Annotation; bool matchesQuery = false; foreach (AnnotationResource resource in annotation.Anchors) { foreach (ContentLocatorBase locator in resource.ContentLocators) { ContentLocator ContentLocator = locator as ContentLocator; if (ContentLocator != null) { if (ContentLocator.StartsWith(anchorLocator)) { matchesQuery = true; } } else { ContentLocatorGroup ContentLocatorGroup = locator as ContentLocatorGroup; if (ContentLocatorGroup != null) { foreach(ContentLocator list in ContentLocatorGroup.Locators) { if (list.StartsWith(anchorLocator)) { matchesQuery = true; break; } } } } if (matchesQuery) { annotations.Add(annotation.Id, annotation); break; } } if (matchesQuery) break; } } return annotations; }
/// <summary> /// Queries the AnnotationStore for annotations that have an anchor /// that contains a locator that begins with the locator parts /// in anchorLocator. /// </summary> /// <param name="anchorLocator">the locator we are looking for</param> /// <returns> /// A list of annotations that have locators in their anchors /// starting with the same locator parts list as of the input locator /// Can return an empty list, but never null. /// </returns> /// <exception cref="ObjectDisposedException">if object has been disposed</exception> public abstract IList<Annotation> GetAnnotations(ContentLocator anchorLocator);
/// <summary> /// Generates a locator part list identifying node. If node has a /// value for DataIdProperty, a locator with a single locator part /// containing the id value is returned. Otherwise null is returned. /// </summary> /// <param name="node">the node to generate a locator for</param> /// <param name="continueGenerating">specifies whether or not generating should /// continue for the rest of the path; always set to true</param> /// <returns>if node has a value for DataIdProperty, a locator with a /// single locator part containing the id value; null otherwise /// </returns> /// <exception cref="ArgumentNullException">node is null</exception> public override ContentLocator GenerateLocator(PathNode node, out bool continueGenerating) { if (node == null) throw new ArgumentNullException("node"); continueGenerating = true; ContentLocator locator = null; ContentLocatorPart newLocatorPart = CreateLocatorPart(node.Node); if (newLocatorPart != null) { locator = new ContentLocator(); locator.Parts.Add(newLocatorPart); } return locator; }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Determines if this list begins with the ContentLocatorParts that /// make up matchList. All ContentLocatorParts in matchList must /// be present and in the same order in this list for /// true to be returned. /// </summary> /// <param name="locator">the list to compare with</param> /// <returns> /// true if this list begins with the ContentLocatorParts in locator; /// false otherwise. If locator is longer than this locator, will /// return false as well. /// </returns> /// <exception cref="ArgumentNullException">locator is null</exception> public bool StartsWith(ContentLocator locator) { if (locator == null) { throw new ArgumentNullException("locator"); } Invariant.Assert(locator.Parts != null, "Locator has null Parts property."); // If this locator is shorter than matchList, then this can't contain matchList. #pragma warning suppress 6506 // Invariant.Assert(locator.Parts != null) if (this.Parts.Count < locator.Parts.Count) { return false; } for (int locatorPartIndex = 0; locatorPartIndex < locator.Parts.Count; locatorPartIndex++) { ContentLocatorPart left = locator.Parts[locatorPartIndex]; ContentLocatorPart right = this.Parts[locatorPartIndex]; // ContentLocator parts can be null so check for that case here if (left == null && right != null) { return false; } if (!left.Matches(right)) { return false; } } return true; }
/// <summary> /// Generates locators identifying 'chunks'. If node is a chunk, /// generates a locator with a single locator part containing a /// fingerprint of the chunk. Otherwise null is returned. /// </summary> /// <param name="node">the node to generate a locator for</param> /// <param name="continueGenerating">return flag indicating whether the search /// should continue (presumably because the search was not exhaustive). /// This processor will always return true because it is possible to locate /// parts of the node (if it is FixedPage or FixedPageProxy)</param> /// <returns>if node is a FixedPage or FixedPageProxy, a ContentLocator /// with a single locator part containing the page number; null if node is not /// FixedPage or FixedPageProxy </returns> /// <exception cref="ArgumentNullException">node is null</exception> /// <exception cref="ArgumentException">node points to a Document Page View which /// doesn't contain a FixedDocumentPage</exception> public override ContentLocator GenerateLocator(PathNode node, out bool continueGenerating) { if (node == null) throw new ArgumentNullException("node"); // Initial value continueGenerating = true; ContentLocator locator = null; DocumentPageView dpv = node.Node as DocumentPageView; int pageNb = -1; if (dpv != null) { // Only produce locator parts for FixedDocumentPages if (dpv.DocumentPage is FixedDocumentPage || dpv.DocumentPage is FixedDocumentSequenceDocumentPage) { pageNb = dpv.PageNumber; } } else { FixedTextSelectionProcessor.FixedPageProxy fPage = node.Node as FixedTextSelectionProcessor.FixedPageProxy; if (fPage != null) { pageNb = fPage.Page; } } if (pageNb >= 0) { locator = new ContentLocator(); ContentLocatorPart locatorPart = CreateLocatorPart(pageNb); locator.Parts.Add(locatorPart); } return locator; }
/// <summary> /// Queries the Xml stream for annotations that have an anchor /// that contains a locator that begins with the locator parts /// in anchorLocator. /// </summary> /// <param name="anchorLocator">the locator we are looking for</param> /// <returns> /// A list of annotations that have locators in their anchors /// starting with the same locator parts list as of the input locator /// If no such annotations an empty list will be returned. The method /// never returns null. /// </returns> /// <exception cref="ObjectDisposedException">if object has been Disposed</exception> /// <exception cref="InvalidOperationException">the stream is null</exception> public override IList<Annotation> GetAnnotations(ContentLocator anchorLocator) { // First we generate the XPath expression if (anchorLocator == null) throw new ArgumentNullException("anchorLocator"); if (anchorLocator.Parts == null) throw new ArgumentNullException("anchorLocator.Parts"); //fire trace event EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.GetAnnotationByLocBegin); IList<Annotation> annotations = null; try { string query = @"//" + AnnotationXmlConstants.Prefixes.CoreSchemaPrefix + ":" + AnnotationXmlConstants.Elements.ContentLocator; if (anchorLocator.Parts.Count > 0) { query += @"/child::*[1]/self::"; for (int i = 0; i < anchorLocator.Parts.Count; i++) { if (anchorLocator.Parts[i] != null) { if (i > 0) { query += @"/following-sibling::"; } string fragment = anchorLocator.Parts[i].GetQueryFragment(_namespaceManager); if (fragment != null) { query += fragment; } else { query += "*"; } } } } query += @"/ancestor::" + AnnotationXmlConstants.Prefixes.CoreSchemaPrefix + ":Anchors/ancestor::" + AnnotationXmlConstants.Prefixes.CoreSchemaPrefix + ":Annotation"; annotations = InternalGetAnnotations(query, anchorLocator); } finally { //fire trace event EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.GetAnnotationByLocEnd); } return annotations; }
/// <summary> /// Do the GetAnnotations work inside a lock statement for thread safety reasons /// </summary> /// <param name="query"></param> /// <param name="anchorLocator"></param> /// <returns></returns> private IList<Annotation> InternalGetAnnotations(string query, ContentLocator anchorLocator) { // anchorLocator being null is handled appropriately below Invariant.Assert(query != null, "Parameter 'query' is null."); lock (SyncRoot) { CheckStatus(); List<Guid> annotationIds = FindAnnotationIds(query); Dictionary<Guid, Annotation> annotations = null; // Now, get the annotations in the map that satisfies the query criterion if (anchorLocator == null) { annotations = _storeAnnotationsMap.FindAnnotations(); } else { annotations = _storeAnnotationsMap.FindAnnotations(anchorLocator); } // merge both query results return MergeAndCacheAnnotations(annotations, annotationIds); } }
private static IList<IAttachedAnnotation> GetSpannedAnnotationsForFixed(AnnotationService service, int startPage, int endPage) { Invariant.Assert(service != null, "Need non-null service to get spanned annotations for fixed content."); FixedPageProcessor processor = service.LocatorManager.GetSubTreeProcessorForLocatorPart(FixedPageProcessor.CreateLocatorPart(0)) as FixedPageProcessor; Invariant.Assert(processor != null, "FixedPageProcessor should be available if we are processing fixed content."); List<IAttachedAnnotation> attachedAnnotations = null; List<Annotation> annotations = new List<Annotation>(); try { // Turn resolving of non-visible anchors on processor.UseLogicalTree = true; // For each non-visible page, query the store for annotations on that page for (int pageNumber = startPage; pageNumber <= endPage; pageNumber++) { ContentLocator locator = new ContentLocator(); locator.Parts.Add(FixedPageProcessor.CreateLocatorPart(pageNumber)); AddRange(annotations, service.Store.GetAnnotations(locator)); } attachedAnnotations = ResolveAnnotations(service, annotations); } finally { // Turn resolving of non-visible anchors off again processor.UseLogicalTree = false; } return attachedAnnotations; }