public GraphNodePath Clone(IGraphNode newRoot) { var clone = new GraphNodePath(newRoot, Math.Max(path.Count, DefaultCapacity)); clone.path.AddRange(path); return(clone); }
/// <summary> /// Visits a hierarchy of node, starting by the given root node. /// </summary> /// <param name="node">The root node of the visit</param> /// <param name="memberNode">The member content containing the node to visit, if relevant. This is used to properly check if the root node should be visited.</param> /// <param name="initialPath">The initial path of the root node, if this visit occurs in the context of a sub-hierarchy. Can be null.</param> public virtual void Visit([NotNull] IGraphNode node, [CanBeNull] MemberNode memberNode = null, [CanBeNull] GraphNodePath initialPath = null) { if (node == null) { throw new ArgumentNullException(nameof(node)); } CurrentPath = initialPath ?? new GraphNodePath(node); RootNode = node; VisitNode(node); RootNode = null; }
public static GraphNodePath From(IGraphNode root, [NotNull] MemberPath memberPath, out NodeIndex index) { if (memberPath == null) { throw new ArgumentNullException(nameof(memberPath)); } var result = new GraphNodePath(root); index = NodeIndex.Empty; var memberPathItems = memberPath.Decompose(); for (int i = 0; i < memberPathItems.Count; i++) { var memberPathItem = memberPathItems[i]; bool lastItem = i == memberPathItems.Count - 1; if (memberPathItem.MemberDescriptor != null) { result.PushMember(memberPathItem.MemberDescriptor.Name); } else if (memberPathItem.GetIndex() != null) { var localIndex = new NodeIndex(memberPathItem.GetIndex()); if (lastItem) { // If last item, we directly return the index rather than add it to the path index = localIndex; } else { result.PushIndex(localIndex); } } // Don't apply Target on last item if (!lastItem) { // If this is a reference, add a target element to the path var node = result.GetNode(); var objectReference = (node as IMemberNode)?.TargetReference; if (objectReference?.TargetNode != null) { result.PushTarget(); } } } return(result); }
public GraphNodePath GetParent() { if (IsEmpty) { return(null); } var result = new GraphNodePath(RootNode, path.Count - 1); for (var i = 0; i < path.Count - 1; ++i) { result.path.Add(path[i]); } return(result); }
private void ContentFinalizeChange(object sender, [NotNull] INodeChangeEventArgs e) { var visitor = CreateVisitor(); visitor.Visiting += (node, path) => RegisterNode(node); switch (e.ChangeType) { case ContentChangeType.ValueChange: case ContentChangeType.CollectionUpdate: // The changed node itself is still valid, we don't want to re-register it visitor.SkipRootNode = true; visitor.Visit(e.Node); // TODO: In case of CollectionUpdate we could probably visit only the target node of the corresponding index break; case ContentChangeType.CollectionAdd: if (e.Node.IsReference && e.NewValue != null) { var objectNode = (IObjectNode)e.Node; IGraphNode addedNode; Index index; var arg = (ItemChangeEventArgs)e; if (!arg.Index.IsEmpty) { index = arg.Index; addedNode = objectNode.ItemReferences[arg.Index].TargetNode; } else { // TODO: review this var reference = objectNode.ItemReferences.First(x => x.TargetNode.Retrieve() == e.NewValue); index = reference.Index; addedNode = reference.TargetNode; } if (addedNode != null && visitor.ShouldVisitTargetItem(objectNode, index)) { var path = new GraphNodePath(e.Node); path.PushIndex(index); visitor.Visit(addedNode, e.Node as MemberNode, path); } } break; } }
/// <inheritdoc/> public bool Equals(GraphNodePath other) { if (ReferenceEquals(null, other)) { return(false); } if (ReferenceEquals(this, other)) { return(true); } if (!Equals(RootNode, other.RootNode) || path.Count != other.path.Count) { return(false); } for (var i = 0; i < path.Count; ++i) { if (!path[i].EqualsInPath(other.path[i])) { return(false); } } return(true); }
public GraphNodePathEnumerator(GraphNodePath path) { this.path = path; }