/// <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); }
// 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); }
/// <summary> /// Deserializes an Resource from the XmlReader passed in. /// </summary> /// <param name="reader">reader to deserialize from</param> /// <exception cref="ArgumentNullException">reader is null</exception> public void ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } XmlDocument doc = new XmlDocument(); ReadAttributes(reader); if (!reader.IsEmptyElement) { reader.Read(); // Reads the remainder of "Resource" start tag while (!(AnnotationXmlConstants.Elements.Resource == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { if (AnnotationXmlConstants.Elements.ContentLocatorGroup == reader.LocalName) { ContentLocatorBase locator = (ContentLocatorBase)LocatorGroupSerializer.Deserialize(reader); InternalLocators.Add(locator); } else if (AnnotationXmlConstants.Elements.ContentLocator == reader.LocalName) { ContentLocatorBase locator = (ContentLocatorBase)ListSerializer.Deserialize(reader); InternalLocators.Add(locator); } else if (XmlNodeType.Element == reader.NodeType) { XmlElement element = doc.ReadNode(reader) as XmlElement; InternalContents.Add(element); } else { // The resource must contain a non-XmlElement child such as plain // text which is not part of the schema. throw new XmlException(SR.Get(SRID.InvalidXmlContent, AnnotationXmlConstants.Elements.Resource)); } } } reader.Read(); // Reads the end of the "Resource" element (or whole element if empty) }
// 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); }
/// <summary>Deserializes the <see cref="T:System.Windows.Annotations.AnnotationResource" /> from a specified <see cref="T:System.Xml.XmlReader" />.</summary> /// <param name="reader">The XML reader to deserialize the <see cref="T:System.Windows.Annotations.AnnotationResource" /> from.</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.AnnotationResource" /> is not valid.</exception> // Token: 0x060062A1 RID: 25249 RVA: 0x001BADB8 File Offset: 0x001B8FB8 public void ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } XmlDocument xmlDocument = new XmlDocument(); this.ReadAttributes(reader); if (!reader.IsEmptyElement) { reader.Read(); while (!("Resource" == reader.LocalName) || XmlNodeType.EndElement != reader.NodeType) { if ("ContentLocatorGroup" == reader.LocalName) { ContentLocatorBase item = (ContentLocatorBase)AnnotationResource.LocatorGroupSerializer.Deserialize(reader); this.InternalLocators.Add(item); } else if ("ContentLocator" == reader.LocalName) { ContentLocatorBase item2 = (ContentLocatorBase)AnnotationResource.ListSerializer.Deserialize(reader); this.InternalLocators.Add(item2); } else { if (XmlNodeType.Element != reader.NodeType) { throw new XmlException(SR.Get("InvalidXmlContent", new object[] { "Resource" })); } XmlElement item3 = xmlDocument.ReadNode(reader) as XmlElement; this.InternalContents.Add(item3); } } } reader.Read(); }
/// <summary> /// Resolves a locator starting on a specified locator part with a specified tree node. /// The tree node can optionally be skipped (if some previous locator part has already /// matched it) in which case the resolution starts with its children. /// </summary> /// <param name="locator">the locator to resolve</param> /// <param name="offset">the index of the first locator part to resolve</param> /// <param name="startNode">the node to start the resolution at</param> /// <param name="skipStartNode">specifies whether to start with the startNode or its children</param> /// <param name="attachmentLevel">return value specifying how successful the resolution was</param> /// <returns>the attached anchor the locator was resolved to</returns> /// <exception cref="InvalidOperationException">if a locator set is resolved and the individual selections /// can't be merged</exception> private Object InternalResolveLocator(ContentLocatorBase locator, int offset, DependencyObject startNode, bool skipStartNode, out AttachmentLevel attachmentLevel) { Debug.Assert(locator != null, "locator can not be null"); Debug.Assert(startNode != null, "startNode can not be null"); // Set it to unresolved initially attachmentLevel = AttachmentLevel.Full; Object selection = null; ContentLocatorGroup locatorGroup = locator as ContentLocatorGroup; ContentLocator realLocator = locator as ContentLocator; AttachmentLevel individualAttachmentLevel = AttachmentLevel.Unresolved; // If only one locator part left, it might represent a selection so we take // care of that case before trying to resolve the locator part if (realLocator != null && offset == realLocator.Parts.Count - 1) { ContentLocatorPart locatorPart = realLocator.Parts[offset]; SelectionProcessor selProcessor = GetSelectionProcessorForLocatorPart(locatorPart); if (selProcessor != null) { selection = selProcessor.ResolveLocatorPart(locatorPart, startNode, out individualAttachmentLevel); attachmentLevel = individualAttachmentLevel; // No node has actually been matched in this case so we // return the default Unresolved (set at top of method). // Its up to the caller to know if the node and // index passed in represented an incomplete resolution. return selection; } } IList<ContentLocator> locators = null; // Setup the locators and other inputs before the loop. Normal locators // are put in an array of locators (with one element). LocatorGroups have // their Locators collection used. if (locatorGroup == null) { Debug.Assert(offset >= 0 && offset < realLocator.Parts.Count, "offset out of range"); locators = new List <ContentLocator> (1); locators.Add(realLocator); } else { // If there is a service, start at its root. AnnotationService svc = AnnotationService.GetService(startNode); if (svc != null) { startNode = svc.Root; } locators = locatorGroup.Locators; // Always start resolving locator groups from the beginning // and use the node the service is enabled on to start offset = 0; skipStartNode = false; } bool middlePortionExists = true; if (locators.Count > 0) { // Otherwise we need to resolve each of the locators in the locator set // and then try to merge the anchors that are returned ResolvingLocatorState data = ResolveSingleLocator(ref selection, ref attachmentLevel, AttachmentLevel.StartPortion, locators[0], offset, startNode, skipStartNode); // Special case - when there is only one locator we simply use the anchor and level // returned from resolving that single locator if (locators.Count == 1) { selection = data.AttachedAnchor; attachmentLevel = data.AttachmentLevel; } else { // Resolve all locators after the first and before the last if (locators.Count > 2) { AttachmentLevel tempLevel = AttachmentLevel.Unresolved; AttachmentLevel savedLevel = attachmentLevel; for (int i = 1; i < locators.Count - 1; i++) { data = ResolveSingleLocator(ref selection, ref attachmentLevel, AttachmentLevel.MiddlePortion, locators[i], offset, startNode, skipStartNode); //if there are >1 middle locators some of them might be resolved, some other - not //if even one middle locator is resolved we should save its attachmenLevel if ((tempLevel == AttachmentLevel.Unresolved) || ((attachmentLevel & AttachmentLevel.MiddlePortion) != 0)) tempLevel = attachmentLevel; attachmentLevel = savedLevel; } attachmentLevel = tempLevel; } else { // We make note that there were no middle portion locators middlePortionExists = false; } // Process the last locator data = ResolveSingleLocator(ref selection, ref attachmentLevel, AttachmentLevel.EndPortion, locators[locators.Count - 1], offset, startNode, skipStartNode); // If no locators exists for the middle portion we need to make // sure its not the only portion left on. if (!middlePortionExists && attachmentLevel == AttachmentLevel.MiddlePortion) { attachmentLevel &= ~AttachmentLevel.MiddlePortion; } //if start and end is resolved we consider this as fully resolved //this will handle the case of empty middle page in fixed if (attachmentLevel == (AttachmentLevel.StartPortion | AttachmentLevel.EndPortion)) attachmentLevel = AttachmentLevel.Full; } } else { // There are no locators to resolve attachmentLevel = AttachmentLevel.Unresolved; } return selection; }
/// <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> /// Produces an anchor spanning the content specified by 'locator'. /// This method traverses the tree and, using the registered /// processors, resolves the locator in the current element tree. /// </summary> /// <param name="locator">the locator to be resolved</param> /// <param name="offset">the index of the locator part to begin resolution with, ignored for /// LocatorGroups which always start with the first locator part</param> /// <param name="startNode">the tree node to start the resolution from</param> /// <param name="attachmentLevel">type of the returned anchor</param> /// <returns>an anchor that spans the content specified by locator; may return /// null if the locator could not be resolved (in which case type is set to /// AttachmentLevel.Unresolved</returns> /// <exception cref="ArgumentNullException">locator or startNode are null</exception> /// <exception cref="ArgumentException">offset is negative or greater than /// locator.Count - 1</exception> public Object ResolveLocator(ContentLocatorBase locator, int offset, DependencyObject startNode, out AttachmentLevel attachmentLevel) { VerifyAccess(); if (locator == null) throw new ArgumentNullException("locator"); if (startNode == null) throw new ArgumentNullException("startNode"); // Offset need only be checked for Locators ContentLocator realLocator = locator as ContentLocator; if (realLocator != null) { if (offset < 0 || offset >= realLocator.Parts.Count) throw new ArgumentOutOfRangeException("offset"); } return InternalResolveLocator(locator, offset, startNode, false /*skipStartNode*/, out attachmentLevel); }
/// <summary> /// Adds the additionalLocators to the end of initialLocator. If /// there are more than one additional locators, clones of /// initialLocator are created. This method may be destructive - /// the locators passed in may be modified. /// </summary> /// <param name="initialLocator">the locator to append the additional locators to</param> /// <param name="additionalLocators">array of locators that need to be appended</param> /// <returns>list of merged locators</returns> private IList<ContentLocatorBase> Merge(ContentLocatorBase initialLocator, IList<ContentLocatorBase> additionalLocators) { if (additionalLocators == null || additionalLocators.Count == 0) { List<ContentLocatorBase> res = new List<ContentLocatorBase>(1); res.Add(initialLocator); return res; } for (int i = 1; i < additionalLocators.Count; i++) { additionalLocators[i] = ((ContentLocatorBase)initialLocator.Clone()).Merge(additionalLocators[i]); } // Avoid making one too many clones... additionalLocators[0] = initialLocator.Merge(additionalLocators[0]); return additionalLocators; }
/// <summary> /// Internal Merge method used by the LocatorManager as it builds up /// Locators. We don't expose these methods publicly because they /// are of little use and are optimized for use by the LM (e.g., we /// know the arguments aren't owned by anyone and can be modified in /// place). /// </summary> /// <param name="other">the ContentLocatorBase to merge</param> /// <returns>the resulting ContentLocatorBase (may be the same object the method /// was called on for perf reasons)</returns> internal abstract ContentLocatorBase Merge(ContentLocatorBase other);
/// <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; }