Example #1
0
        private GraphNodePath Clone(IGraphNode newRoot, bool isEmpty)
        {
            var clone = new GraphNodePath(newRoot, isEmpty, Math.Max(path.Count, DefaultCapacity));

            clone.path.AddRange(path);
            return(clone);
        }
        private GraphNodePath Clone(IGraphNode newRoot, bool newTargetIsRootNode)
        {
            var clone = new GraphNodePath(newRoot, newTargetIsRootNode);

            clone.path.AddRange(path);
            return(clone);
        }
Example #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ObservableModelNode"/> class.
        /// </summary>
        /// <param name="ownerViewModel">The <see cref="ObservableViewModel"/> that owns the new <see cref="ObservableModelNode"/>.</param>
        /// <param name="baseName">The base name of this node. Can be null if <see cref="index"/> is not. If so a name will be automatically generated from the index.</param>
        /// <param name="isPrimitive">Indicate whether this node should be considered as a primitive node.</param>
        /// <param name="modelNode">The model node bound to the new <see cref="ObservableModelNode"/>.</param>
        /// <param name="graphNodePath">The <see cref="GraphNodePath"/> corresponding to the given <see cref="modelNode"/>.</param>
        /// <param name="index">The index of this content in the model node, when this node represent an item of a collection. <c>null</c> must be passed otherwise</param>
        protected ObservableModelNode(ObservableViewModel ownerViewModel, string baseName, bool isPrimitive, IGraphNode modelNode, GraphNodePath graphNodePath, object index = null)
            : base(ownerViewModel, baseName, index)
        {
            if (modelNode == null) throw new ArgumentNullException(nameof(modelNode));
            if (baseName == null && index == null)
                throw new ArgumentException("baseName and index can't be both null.");

            this.isPrimitive = isPrimitive;
            SourceNode = modelNode;
            // By default we will always combine items of list of primitive items.
            CombineMode = index != null && isPrimitive ? CombineMode.AlwaysCombine : CombineMode.CombineOnlyForAll;
            SourceNodePath = graphNodePath;

            // Override display name if available
            var memberDescriptor = GetMemberDescriptor() as MemberDescriptorBase;
            if (memberDescriptor != null)
            {
                if (index == null)
                {
                    var displayAttribute = TypeDescriptorFactory.Default.AttributeRegistry.GetAttribute<DisplayAttribute>(memberDescriptor.MemberInfo);
                    if (!string.IsNullOrEmpty(displayAttribute?.Name))
                    {
                        DisplayName = displayAttribute.Name;
                    }
                    IsReadOnly = !memberDescriptor.HasSet;
                }
            }
        }
Example #4
0
 protected virtual void UnregisterNode(IGraphNode node, GraphNodePath path)
 {
     node.Content.PrepareChange  -= ContentPrepareChange;
     node.Content.FinalizeChange -= ContentFinalizeChange;
     node.Content.Changing       -= ContentChanging;
     node.Content.Changed        -= ContentChanged;
 }
 public ModelNodeCommandWrapper(IViewModelServiceProvider serviceProvider, INodeCommand nodeCommand, GraphNodePath nodePath, IEnumerable<IDirtiable> dirtiables)
     : base(serviceProvider, dirtiables)
 {
     if (nodeCommand == null) throw new ArgumentNullException(nameof(nodeCommand));
     NodePath = nodePath;
     NodeCommand = nodeCommand;
     Service = serviceProvider.Get<ObservableViewModelService>();
 }
Example #6
0
 public GraphNodePathEnumerator(GraphNodePath path)
 {
     if (!path.IsValid)
     {
         throw new InvalidOperationException("The node path is invalid.");
     }
     this.path = path;
 }
 public ModelNodeCommandWrapper(IViewModelServiceProvider serviceProvider, INodeCommand nodeCommand, GraphNodePath nodePath, Index index)
     : base(serviceProvider)
 {
     if (nodeCommand == null) throw new ArgumentNullException(nameof(nodeCommand));
     NodePath = nodePath;
     Index = index;
     NodeCommand = nodeCommand;
 }
Example #8
0
        /// <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="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(IGraphNode node, GraphNodePath initialPath = null)
        {
            var path = initialPath ?? new GraphNodePath(node);

            rootNode = node;
            VisitNode(node, path);
            rootNode = null;
        }
 protected override void VisitNode(IGraphNode node, GraphNodePath currentPath)
 {
     var targetNode = linker.FindTarget(node);
     // Override the target node, in case FindTarget returned a different one.
     VisitedLinks[node] = targetNode;
     linker.LinkNodes(node, targetNode);
     base.VisitNode(node, currentPath);
 }
Example #10
0
            protected override void VisitNode(IGraphNode node, GraphNodePath currentPath)
            {
                var targetNode = linker.FindTarget(node);

                // Override the target node, in case FindTarget returned a different one.
                VisitedLinks[node] = targetNode;
                linker.LinkNodes(node, targetNode);
                base.VisitNode(node, currentPath);
            }
Example #11
0
        /// <summary>
        /// Visits the <see cref="ObjectReference"/> contained in the given node, if any.
        /// </summary>
        /// <param name="node">The node being visited.</param>
        /// <param name="currentPath">The path of the node being visited.</param>
        public virtual void VisitSingleTarget(IGraphNode node, GraphNodePath currentPath)
        {
            var objectReference = node.Content.Reference as ObjectReference;

            if (objectReference?.TargetNode != null)
            {
                var targetPath = currentPath.PushTarget();
                VisitReference(node, objectReference, targetPath);
            }
        }
 /// <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="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(IGraphNode node, GraphNodePath initialPath = null)
 {
     var path = initialPath ?? new GraphNodePath(node);
     RootNode = node;
     if (ShouldVisitNode(null, node))
     {
         VisitNode(node, path);
     }
     RootNode = null;
 }
Example #13
0
 /// <summary>
 /// Visits the children of the given node.
 /// </summary>
 /// <param name="node">The node being visited.</param>
 /// <param name="currentPath">The path of the node being visited.</param>
 public virtual void VisitChildren(IGraphNode node, GraphNodePath currentPath)
 {
     foreach (var child in node.Children)
     {
         var childPath = currentPath.PushMember(child.Name);
         if (ShouldVisitNode(child, childPath))
         {
             VisitNode(child, childPath);
         }
     }
 }
 /// <summary>
 /// Visits the children of the given node.
 /// </summary>
 /// <param name="node">The node being visited.</param>
 /// <param name="currentPath">The path of the node being visited.</param>
 protected virtual void VisitChildren(IGraphNode node, GraphNodePath currentPath)
 {
     foreach (var child in node.Children)
     {
         var childPath = currentPath.PushMember(child.Name);
         if (ShouldVisitNode(child.Content as MemberContent, child))
         {
             VisitNode(child, childPath);
         }
     }
 }
Example #15
0
        /// <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="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(IGraphNode node, GraphNodePath initialPath = null)
        {
            var path = initialPath ?? new GraphNodePath(node);

            RootNode = node;
            if (ShouldVisitNode(node, path))
            {
                VisitNode(node, path);
            }
            RootNode = null;
        }
Example #16
0
        protected virtual void UnregisterNode(IGraphNode node, GraphNodePath path)
        {
            if (!registeredNodes.ContainsKey(node))
                throw new InvalidOperationException("Node not registered");

            registeredNodes.Remove(node);
            node.Content.PrepareChange -= ContentPrepareChange;
            node.Content.FinalizeChange -= ContentFinalizeChange;
            node.Content.Changing -= ContentChanging;
            node.Content.Changed -= ContentChanged;
        }
 /// <summary>
 /// Visits the children of the given node.
 /// </summary>
 /// <param name="node">The node being visited.</param>
 /// <param name="currentPath">The path of the node being visited.</param>
 protected virtual void VisitChildren(IObjectNode node, GraphNodePath currentPath)
 {
     foreach (var child in node.Members)
     {
         var childPath = currentPath.PushMember(child.Name);
         if (ShouldVisitNode(child, child))
         {
             VisitNode(child, childPath);
         }
     }
 }
Example #18
0
 /// <summary>
 /// Visits a single node.
 /// </summary>
 /// <param name="node">The node being visited.</param>
 /// <param name="currentPath">The path of the node being visited.</param>
 /// <remarks>This method is in charge of pursuing the visit with the children and references of the given node, as well as raising the <see cref="Visiting"/> event.</remarks>
 protected virtual void VisitNode(IGraphNode node, GraphNodePath currentPath)
 {
     visitedNodes.Add(node);
     if (node != RootNode || !SkipRootNode)
     {
         Visiting?.Invoke(node, currentPath);
     }
     VisitChildren(node, currentPath);
     VisitSingleTarget(node, currentPath);
     VisitEnumerableTargets(node, currentPath);
     visitedNodes.Remove(node);
 }
Example #19
0
        protected virtual void RegisterNode(IGraphNode node, GraphNodePath path)
        {
            if (registeredNodes.ContainsKey(node))
                throw new InvalidOperationException("Node already registered");

            registeredNodes.Add(node, path);

            node.Content.PrepareChange += ContentPrepareChange;
            node.Content.FinalizeChange += ContentFinalizeChange;
            node.Content.Changing += ContentChanging;
            node.Content.Changed += ContentChanged;
        }
Example #20
0
        public GraphNodePath SubPath(int nodeCount)
        {
            if (nodeCount < 0 || nodeCount >= path.Count)
            {
                throw new ArgumentOutOfRangeException(nameof(nodeCount));
            }

            var subPath = new GraphNodePath(RootNode);

            subPath.path.AddRange(path.Take(nodeCount));
            return(subPath);
        }
 /// <summary>
 /// Visits a single node.
 /// </summary>
 /// <param name="node">The node being visited.</param>
 /// <param name="currentPath">The path of the node being visited.</param>
 /// <remarks>This method is in charge of pursuing the visit with the children and references of the given node, as well as raising the <see cref="Visiting"/> event.</remarks>
 protected virtual void VisitNode(IGraphNode node, GraphNodePath currentPath)
 {
     visitedNodes.Add(node);
     if (node != RootNode || !SkipRootNode)
     {
         Visiting?.Invoke(node, currentPath);
     }
     VisitChildren(node, currentPath);
     VisitSingleTarget(node, currentPath);
     VisitEnumerableTargets(node, currentPath);
     visitedNodes.Remove(node);
 }
Example #22
0
        public GraphNodePath PushChildPath(GraphNodePath childPath)
        {
            if (childPath.IsEmpty)
            {
                return(Clone());
            }

            var result = Clone(RootNode, false);

            result.path.AddRange(childPath.path);
            return(result);
        }
Example #23
0
            public override void VisitChildren(IGraphNode node, GraphNodePath currentPath)
            {
                IGraphNode targetNodeParent;

                if (VisitedLinks.TryGetValue(node, out targetNodeParent))
                {
                    foreach (var child in node.Children)
                    {
                        VisitedLinks.Add(child, targetNodeParent?.GetChild(child.Name));
                    }
                }
                base.VisitChildren(node, currentPath);
            }
Example #24
0
        protected virtual void UnregisterNode(IGraphNode node, GraphNodePath path)
        {
            if (!registeredNodes.ContainsKey(node))
            {
                throw new InvalidOperationException("Node not registered");
            }

            registeredNodes.Remove(node);
            node.Content.PrepareChange  -= ContentPrepareChange;
            node.Content.FinalizeChange -= ContentFinalizeChange;
            node.Content.Changing       -= ContentChanging;
            node.Content.Changed        -= ContentChanged;
        }
Example #25
0
        /// <summary>
        /// Visits the <see cref="ReferenceEnumerable"/> contained in the given node, if any.
        /// </summary>
        /// <param name="node">The node being visited.</param>
        /// <param name="currentPath">The path of the node being visited.</param>
        public virtual void VisitEnumerableTargets(IGraphNode node, GraphNodePath currentPath)
        {
            var enumerableReference = node.Content.Reference as ReferenceEnumerable;

            if (enumerableReference != null)
            {
                foreach (var reference in enumerableReference.Where(x => x.TargetNode != null))
                {
                    var targetPath = currentPath.PushIndex(reference.Index);
                    VisitReference(node, reference, targetPath);
                }
            }
        }
Example #26
0
        protected virtual void RegisterNode(IGraphNode node, GraphNodePath path)
        {
            if (registeredNodes.ContainsKey(node))
            {
                throw new InvalidOperationException("Node already registered");
            }

            registeredNodes.Add(node, path);

            node.Content.PrepareChange  += ContentPrepareChange;
            node.Content.FinalizeChange += ContentFinalizeChange;
            node.Content.Changing       += ContentChanging;
            node.Content.Changed        += ContentChanged;
        }
Example #27
0
        public GraphNodePath GetParent()
        {
            if (IsEmpty)
            {
                return(null);
            }

            var result = new GraphNodePath(RootNode, path.Count == 1, path.Count - 1);

            for (var i = 0; i < path.Count - 1; ++i)
            {
                result.path.Add(path[i]);
            }
            return(result);
        }
 protected override void VisitChildren(IGraphNode node, GraphNodePath currentPath)
 {
     IGraphNode targetNodeParent;
     if (VisitedLinks.TryGetValue(node, out targetNodeParent))
     {
         foreach (var child in node.Children)
         {
             if (ShouldVisitNode(child.Content as MemberContent, child))
             {
                 string name = child.Name;
                 VisitedLinks.Add(child, targetNodeParent?.TryGetChild(name));
             }
         }
     }
     base.VisitChildren(node, currentPath);
 }
            protected override void VisitChildren(IObjectNode node, GraphNodePath currentPath)
            {
                IContentNode targetNodeParent;

                if (VisitedLinks.TryGetValue(node, out targetNodeParent))
                {
                    foreach (var child in node.Members)
                    {
                        if (ShouldVisitNode(child, child))
                        {
                            string name = child.Name;
                            VisitedLinks.Add(child, ((IObjectNode)targetNodeParent)?.TryGetChild(name));
                        }
                    }
                }
                base.VisitChildren(node, currentPath);
            }
Example #30
0
        private void ContentFinalizeChange(object sender, ContentChangeEventArgs e)
        {
            var node = e.Content.OwnerNode as IGraphNode;

            if (node != null)
            {
                var visitor = new GraphVisitorBase();
                visitor.Visiting   += (node1, path) => RegisterNode(node1);
                visitor.ShouldVisit = shouldRegisterNode;
                switch (e.ChangeType)
                {
                case ContentChangeType.ValueChange:
                    // The changed node itself is still valid, we don't want to re-register it
                    visitor.SkipRootNode = true;
                    visitor.Visit(node);
                    break;

                case ContentChangeType.CollectionAdd:
                    if (node.Content.IsReference && e.NewValue != null)
                    {
                        IGraphNode addedNode;
                        Index      index;
                        if (!e.Index.IsEmpty)
                        {
                            index     = e.Index;
                            addedNode = node.Content.Reference.AsEnumerable[e.Index].TargetNode;
                        }
                        else
                        {
                            var reference = node.Content.Reference.AsEnumerable.First(x => x.TargetNode.Content.Retrieve() == e.NewValue);
                            index     = reference.Index;
                            addedNode = reference.TargetNode;
                        }

                        if (addedNode != null)
                        {
                            var path = new GraphNodePath(node).PushIndex(index);
                            visitor.Visit(addedNode, path);
                        }
                    }
                    break;
                }
            }

            FinalizeChange?.Invoke(sender, new GraphContentChangeEventArgs(e));
        }
 public static YamlAssetPath ConvertPath(GraphNodePath path, int inNonIdentifiableType)
 {
     var currentNode = (AssetNode)path.RootNode;
     var result = new YamlAssetPath();
     var i = 0;
     foreach (var item in path.Path)
     {
         switch (item.Type)
         {
             case GraphNodePath.ElementType.Member:
                 var member = (string)item.Value;
                 result.PushMember(member);
                 currentNode = (AssetNode)((IGraphNode)currentNode).TryGetChild(member);
                 break;
             case GraphNodePath.ElementType.Target:
                 if (i < path.Path.Count - 1)
                 {
                     currentNode = (AssetNode)((IGraphNode)currentNode).Target;
                 }
                 break;
             case GraphNodePath.ElementType.Index:
                 var index = (Index)item.Value;
                 if (inNonIdentifiableType > 0 || currentNode.IsNonIdentifiableCollectionContent)
                 {
                     result.PushIndex(index.Value);
                 }
                 else
                 {
                     var id = currentNode.IndexToId(index);
                     // Create a new id if we don't have any so far
                     if (id == ItemId.Empty)
                         id = ItemId.New();
                     result.PushItemId(id);
                 }
                 if (i < path.Path.Count - 1)
                 {
                     currentNode = (AssetNode)((IGraphNode)currentNode).IndexedTarget(index);
                 }
                 break;
             default:
                 throw new ArgumentOutOfRangeException();
         }
         ++i;
     }
     return result;
 }
Example #32
0
        public static GraphNodePath From(IGraphNode root, MemberPath memberPath, out Index index)
        {
            var result = new GraphNodePath(root);

            index = Index.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 = result.PushMember(memberPathItem.MemberDescriptor.Name);
                }
                else if (memberPathItem.GetIndex() != null)
                {
                    var localIndex = new Index(memberPathItem.GetIndex());

                    if (lastItem)
                    {
                        // If last item, we directly return the index rather than add it to the path
                        index = localIndex;
                    }
                    else
                    {
                        result = 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.Content.Reference as ObjectReference;
                    if (objectReference?.TargetNode != null)
                    {
                        result = result.PushTarget();
                    }
                }
            }

            return(result);
        }
Example #33
0
        private void ContentFinalizeChange(object sender, MemberNodeChangeEventArgs e)
        {
            var visitor = new GraphVisitorBase();

            visitor.Visiting   += (node, path) => RegisterNode(node);
            visitor.ShouldVisit = shouldRegisterNode;
            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.Member);
                // TODO: In case of CollectionUpdate we could probably visit only the target node of the corresponding index
                break;

            case ContentChangeType.CollectionAdd:
                if (e.Member.IsReference && e.NewValue != null)
                {
                    IContentNode addedNode;
                    Index        index;
                    if (!e.Index.IsEmpty)
                    {
                        index     = e.Index;
                        addedNode = e.Member.ItemReferences[e.Index].TargetNode;
                    }
                    else
                    {
                        var reference = e.Member.ItemReferences.First(x => x.TargetNode.Retrieve() == e.NewValue);
                        index     = reference.Index;
                        addedNode = reference.TargetNode;
                    }

                    if (addedNode != null)
                    {
                        var path = new GraphNodePath(e.Member).PushIndex(index);
                        visitor.Visit(addedNode, e.Member as MemberContent, path);
                    }
                }
                break;
            }
        }
            protected override void VisitReference(IGraphNode referencer, ObjectReference reference, GraphNodePath targetPath)
            {
                if (ShouldVisitNode(referencer.Content as MemberContent, reference.TargetNode))
                {
                    if (reference.TargetNode != null)
                    {
                        // Prevent re-entrancy in the same object
                        if (VisitedLinks.ContainsKey(reference.TargetNode))
                            return;

                        IGraphNode targetNode;
                        if (VisitedLinks.TryGetValue(referencer, out targetNode))
                        {
                            ObjectReference targetReference = null;
                            if (targetNode != null)
                                targetReference = linker.FindTargetReference(referencer, targetNode, reference);

                            VisitedLinks.Add(reference.TargetNode, targetReference?.TargetNode);
                        }
                    }
                    base.VisitReference(referencer, reference, targetPath);
                }
            }
Example #35
0
        public bool Equals(GraphNodePath other)
        {
            if (ReferenceEquals(null, other))
            {
                return(false);
            }
            if (ReferenceEquals(this, other))
            {
                return(true);
            }
            if (!Equals(RootNode, other.RootNode) || IsEmpty != other.IsEmpty || 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);
        }
        protected override void VisitNode(IGraphNode node, GraphNodePath currentPath)
        {
            var assetNode = (AssetNode)node;

            bool localInNonIdentifiableType = false;
            if ((node.Content.Descriptor as ObjectDescriptor)?.Attributes.OfType<NonIdentifiableCollectionItemsAttribute>().Any() ?? false)
            {
                localInNonIdentifiableType = true;
                inNonIdentifiableType++;
            }

            var path = ConvertPath(currentPath, inNonIdentifiableType);
            if (assetNode.IsContentOverridden())
            {
                Result.Add(path, assetNode.GetContentOverride());
            }

            foreach (var index in assetNode.GetOverriddenItemIndices())
            {
                var id = assetNode.IndexToId(index);
                var itemPath = path.Clone();
                itemPath.PushItemId(id);
                Result.Add(itemPath, assetNode.GetItemOverride(index));
            }
            foreach (var index in assetNode.GetOverriddenKeyIndices())
            {
                var id = assetNode.IndexToId(index);
                var itemPath = path.Clone();
                itemPath.PushIndex(id);
                Result.Add(itemPath, assetNode.GetKeyOverride(index));
            }
            base.VisitNode(node, currentPath);

            if (localInNonIdentifiableType)
                inNonIdentifiableType--;
        }
Example #37
0
 /// <summary>
 /// Create an <see cref="ObservableModelNode{T}"/> that matches the given content type.
 /// </summary>
 /// <param name="ownerViewModel">The <see cref="ObservableViewModel"/> that owns the new <see cref="ObservableModelNode"/>.</param>
 /// <param name="baseName">The base name of this node. Can be null if <see cref="index"/> is not. If so a name will be automatically generated from the index.</param>
 /// <param name="isPrimitive">Indicate whether this node should be considered as a primitive node.</param>
 /// <param name="modelNode">The model node bound to the new <see cref="ObservableModelNode"/>.</param>
 /// <param name="graphNodePath">The <see cref="GraphNodePath"/> corresponding to the given node.</param>
 /// <param name="contentType">The type of content contained by the new <see cref="ObservableModelNode"/>.</param>
 /// <param name="index">The index of this content in the model node, when this node represent an item of a collection. <c>null</c> must be passed otherwise</param>
 /// <returns>A new instance of <see cref="ObservableModelNode{T}"/> instanced with the given content type as generic argument.</returns>
 internal static ObservableModelNode Create(ObservableViewModel ownerViewModel, string baseName, bool isPrimitive, IGraphNode modelNode, GraphNodePath graphNodePath, Type contentType, object index)
 {
     var node = (ObservableModelNode)Activator.CreateInstance(typeof(ObservableModelNode<>).MakeGenericType(contentType), ownerViewModel, baseName, isPrimitive, modelNode, graphNodePath, index);
     return node;
 }
        private void GenerateChildren(IGraphNode targetNode, GraphNodePath targetNodePath)
        {
            // Node representing a member with a reference to another object
            if (SourceNode != targetNode && SourceNode.Content.IsReference)
            {
                var objectReference = SourceNode.Content.Reference as ObjectReference;
                // Discard the children of the referenced object if requested by the property provider
                if (objectReference != null && !Owner.PropertiesProvider.ShouldExpandReference(SourceNode.Content as MemberContent, objectReference))
                    return;

                var refEnum = SourceNode.Content.Reference as ReferenceEnumerable;
                if (refEnum != null)
                {
                    foreach (var reference in refEnum)
                    {
                        // Discard the children of the referenced object if requested by the property provider
                        if (reference != null && !Owner.PropertiesProvider.ShouldExpandReference(SourceNode.Content as MemberContent, reference))
                            return;
                    }
                }
            }

            var dictionary = targetNode.Content.Descriptor as DictionaryDescriptor;
            var list = targetNode.Content.Descriptor as CollectionDescriptor;

            // Node containing a collection of references to other objects
            if (SourceNode == targetNode && targetNode.Content.IsReference)
            {
                var referenceEnumerable = targetNode.Content.Reference as ReferenceEnumerable;
                if (referenceEnumerable != null)
                {
                    // We create one node per item of the collection, unless requested by the property provide to not expand the reference.
                    foreach (var reference in referenceEnumerable)
                    {
                        // The type might be a boxed primitive type, such as float, if the collection has object as generic argument.
                        // In this case, we must set the actual type to have type converter working, since they usually can't convert
                        // a boxed float to double for example. Otherwise, we don't want to have a node type that is value-dependent.
                        var type = reference.TargetNode != null && reference.TargetNode.Content.IsPrimitive ? reference.TargetNode.Content.Type : reference.Type;
                        var observableNode = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, false, targetNode, targetNodePath, type, reference.Index);
                        AddChild(observableNode);
                        observableNode.Initialize();
                    }
                }
            }
            // Node containing a dictionary of primitive values
            else if (dictionary != null && targetNode.Content.Value != null)
            {
                // TODO: there is no way to discard items of such collections, without discarding the collection itself. Could this be needed at some point?
                // We create one node per item of the collection.
                foreach (var key in dictionary.GetKeys(targetNode.Content.Value))
                {
                    var index = new Index(key);
                    var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, true, targetNode, targetNodePath, dictionary.ValueType, index);
                    AddChild(observableChild);
                    observableChild.Initialize();
                }
            }
            // Node containing a list of primitive values
            else if (list != null && targetNode.Content.Value != null)
            {
                // TODO: there is no way to discard items of such collections, without discarding the collection itself. Could this be needed at some point?
                // We create one node per item of the collection.
                for (int i = 0; i < list.GetCollectionCount(targetNode.Content.Value); ++i)
                {
                    var index = new Index(i);
                    var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, true, targetNode, targetNodePath, list.ElementType, index);
                    AddChild(observableChild);
                    observableChild.Initialize();
                }
            }
            // Node containing a single non-reference primitive object
            else
            {
                foreach (var child in targetNode.Children)
                {
                    var memberContent = (MemberContent)child.Content;
                    var descriptor = (MemberDescriptorBase)memberContent.Member;
                    var displayAttribute = TypeDescriptorFactory.Default.AttributeRegistry.GetAttribute<DisplayAttribute>(descriptor.MemberInfo);
                    if (displayAttribute == null || displayAttribute.Browsable)
                    {
                        // The path is the source path here - the target path might contain the target resolution that we don't want at that point
                        if (Owner.PropertiesProvider.ShouldConstructMember(memberContent))
                        {
                            var childPath = targetNodePath.PushMember(child.Name);
                            var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, child.Name, child.Content.IsPrimitive, child, childPath, child.Content.Type, Index.Empty);
                            AddChild(observableChild);
                            observableChild.Initialize();
                        }
                    }
                }
            }
        }
Example #39
0
 private void GenerateChildren(IGraphNode modelNode, GraphNodePath graphNodePath)
 {
     if (modelNode.Content.IsReference && modelNode.Content.ShouldProcessReference)
     {
         var referenceEnumerable = modelNode.Content.Reference as ReferenceEnumerable;
         if (referenceEnumerable != null)
         {
             // If the reference should not be processed, we still need to create an observable node for each entry of the enumerable.
             // These observable nodes will have the same source node that their parent so we use this information to prevent
             // the infinite recursion that could occur due to the fact that these child nodes will have the same model nodes (like primitive types)
             // while holding an enumerable reference.
             //if (modelNode.Content.ShouldProcessReference || ModelNodeParent.sourceNode != modelNode)
             {
                 // Note: we are making a copy of the reference list because it can be updated from the Initialize method of the
                 // observable node in the case of scene objects. Doing this is a hack, but parts of this framework will be redesigned later to improve this
                 foreach (var reference in referenceEnumerable.ToList())
                 {
                     // The type might be a boxed primitive type, such as float, if the collection has object as generic argument.
                     // In this case, we must set the actual type to have type converter working, since they usually can't convert
                     // a boxed float to double for example. Otherwise, we don't want to have a node type that is value-dependent.
                     var type = reference.TargetNode != null && reference.TargetNode.Content.IsPrimitive ? reference.TargetNode.Content.Type : reference.Type;
                     var observableNode = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, false, modelNode, graphNodePath, type, reference.Index);
                     AddChild(observableNode);
                     observableNode.Initialize();
                 }
             }
         }
     }
     else
     {
         var dictionary = modelNode.Content.Descriptor as DictionaryDescriptor;
         var list = modelNode.Content.Descriptor as CollectionDescriptor;
         if (dictionary != null && modelNode.Content.Value != null)
         {
             // Dictionary of primitive objects
             foreach (var key in dictionary.GetKeys(modelNode.Content.Value))
             {
                 var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, true, modelNode, graphNodePath, dictionary.ValueType, key);
                 AddChild(observableChild);
                 observableChild.Initialize();
             }
         }
         else if (list != null && modelNode.Content.Value != null)
         {
             // List of primitive objects
             for (int i = 0; i < list.GetCollectionCount(modelNode.Content.Value); ++i)
             {
                 var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, true, modelNode, graphNodePath, list.ElementType, i);
                 AddChild(observableChild);
                 observableChild.Initialize();
             }
         }
         else
         {
             // Single non-reference primitive object
             foreach (var child in modelNode.Children)
             {
                 var childPath = graphNodePath.GetChildPath(modelNode, child);
                 var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, child.Name, child.Content.IsPrimitive, child, childPath, child.Content.Type, null);
                 AddChild(observableChild);
                 observableChild.Initialize();
             }
         }
     }
 }
Example #40
0
 private static ObservableModelNode DefaultCreateNode(ObservableViewModel viewModel, string baseName, bool isPrimitive, IGraphNode modelNode, GraphNodePath graphNodePath, Type contentType, Index index)
 {
     return ObservableModelNode.Create(viewModel, baseName, isPrimitive, modelNode, graphNodePath, contentType, index);
 }
        /// <summary>
        /// Retrieves the path of the target node if the given source node content holds a reference or a sequence of references, or the given source node path otherwise.
        /// </summary>
        /// <param name="sourceNode">The source node for which to retrieve the target node.</param>
        /// <param name="index">The index of the target node to retrieve, if the source node contains a sequence of references. <see cref="Index.Empty"/> otherwise.</param>
        /// <param name="sourceNodePath">The path to the given <paramref name="sourceNode"/>.</param>
        /// <returns>The path to the corresponding target node if available, or the path to source node itself if it does not contain any reference or if its content should not process references.</returns>
        /// <remarks>This method can return null if the target node is null.</remarks>
        protected static GraphNodePath GetTargetNodePath(IGraphNode sourceNode, Index index, GraphNodePath sourceNodePath)
        {
            if (sourceNode == null) throw new ArgumentNullException(nameof(sourceNode));
            if (sourceNodePath == null) throw new ArgumentNullException(nameof(sourceNodePath));

            var objectReference = sourceNode.Content.Reference as ObjectReference;
            if (objectReference != null)
            {
                return sourceNodePath.PushTarget();
            }

            var referenceEnumerable = sourceNode.Content.Reference as ReferenceEnumerable;
            if (referenceEnumerable != null && !index.IsEmpty)
            {
                return sourceNodePath.PushIndex(index);
            }

            return sourceNodePath.Clone();
        }
Example #42
0
        /// <summary>
        /// Gets all the children of the given node, the nodes it references, and their children, recursively.
        /// </summary>
        /// <param name="graphNode">The node for which to obtain all children.</param>
        /// <param name="rootPath">The path of the root node passed to this method.</param>
        /// <returns>A sequence of node containing all the nodes that are either child or referenced by the given node, recursively.</returns>
        public static IEnumerable <Tuple <IGraphNode, GraphNodePath> > GetAllChildNodes(this IGraphNode graphNode, GraphNodePath rootPath = null)
        {
            var processedNodes = new HashSet <IGraphNode>();
            var nodeStack      = new Stack <Tuple <IGraphNode, GraphNodePath> >();

            nodeStack.Push(Tuple.Create(graphNode, rootPath));

            while (nodeStack.Count > 0)
            {
                var item = nodeStack.Pop();
                var node = item.Item1;
                var path = item.Item2;

                processedNodes.Add(node);
                // We don't want to include the initial node
                if (node != graphNode)
                {
                    yield return(item);
                }

                // Add child nodes
                node.Children.ForEach(x => nodeStack.Push(Tuple.Create(x, path?.Append(node, x, GraphNodePath.ElementType.Member, null))));

                // Add object reference target node
                var objectReference = node.Content.Reference as ObjectReference;
                if (objectReference?.TargetNode != null)
                {
                    nodeStack.Push(Tuple.Create(objectReference.TargetNode, path?.Append(node, objectReference.TargetNode, GraphNodePath.ElementType.Target, null)));
                }

                // Add enumerable reference target nodes
                var enumerableReference = node.Content.Reference as ReferenceEnumerable;
                enumerableReference?.Where(x => x.TargetNode != null).ForEach(x => nodeStack.Push(Tuple.Create(x.TargetNode, path?.Append(node, x.TargetNode, GraphNodePath.ElementType.Index, x.Index))));
            }
        }
 /// <summary>
 /// Visits the <see cref="ReferenceEnumerable"/> contained in the given node, if any.
 /// </summary>
 /// <param name="node">The node being visited.</param>
 /// <param name="currentPath">The path of the node being visited.</param>
 public virtual void VisitEnumerableTargets(IGraphNode node, GraphNodePath currentPath)
 {
     var enumerableReference = node.Content.Reference as ReferenceEnumerable;
     if (enumerableReference != null)
     {
         foreach (var reference in enumerableReference.Where(x => x.TargetNode != null))
         {
             var targetPath = currentPath.PushIndex(reference.Index);
             VisitReference(node, reference, targetPath);
         }
     }
 }
Example #44
0
            protected override void VisitReference(IGraphNode referencer, ObjectReference reference, GraphNodePath targetPath)
            {
                if (reference.TargetNode != null)
                {
                    IGraphNode targetNode;
                    if (VisitedLinks.TryGetValue(referencer, out targetNode))
                    {
                        ObjectReference targetReference = null;
                        if (targetNode != null)
                        {
                            targetReference = linker.FindTargetReference(referencer, targetNode, reference);
                        }

                        VisitedLinks.Add(reference.TargetNode, targetReference?.TargetNode);
                    }
                }
                base.VisitReference(referencer, reference, targetPath);
            }
Example #45
0
            protected override void VisitReference(IGraphNode referencer, ObjectReference reference, GraphNodePath targetPath)
            {
                if (ShouldVisitNode(referencer.Content as MemberContent, reference.TargetNode))
                {
                    if (reference.TargetNode != null)
                    {
                        // Prevent re-entrancy in the same object
                        if (VisitedLinks.ContainsKey(reference.TargetNode))
                        {
                            return;
                        }

                        IGraphNode targetNode;
                        if (VisitedLinks.TryGetValue(referencer, out targetNode))
                        {
                            ObjectReference targetReference = null;
                            if (targetNode != null)
                            {
                                targetReference = linker.FindTargetReference(referencer, targetNode, reference);
                            }

                            VisitedLinks.Add(reference.TargetNode, targetReference?.TargetNode);
                        }
                    }
                    base.VisitReference(referencer, reference, targetPath);
                }
            }
 /// <summary>
 /// Visits the <see cref="ObjectReference"/> contained in the given node, if any.
 /// </summary>
 /// <param name="node">The node being visited.</param>
 /// <param name="currentPath">The path of the node being visited.</param>
 protected virtual void VisitSingleTarget(IGraphNode node, GraphNodePath currentPath)
 {
     var objectReference = node.Content.Reference as ObjectReference;
     if (objectReference?.TargetNode != null)
     {
         var targetPath = currentPath.PushTarget();
         VisitReference(node, objectReference, targetPath);
     }
 }
        private void ContentFinalizeChange(object sender, ContentChangeEventArgs e)
        {
            var node = e.Content.OwnerNode as IGraphNode;
            if (node != null)
            {
                var visitor = new GraphVisitorBase();
                visitor.Visiting += (node1, path) => RegisterNode(node1);
                visitor.ShouldVisit = shouldRegisterNode;
                switch (e.ChangeType)
                {
                    case ContentChangeType.ValueChange:
                        // The changed node itself is still valid, we don't want to re-register it
                        visitor.SkipRootNode = true;
                        visitor.Visit(node);
                        break;
                    case ContentChangeType.CollectionAdd:
                        if (node.Content.IsReference && e.NewValue != null)
                        {
                            IGraphNode addedNode;
                            Index index;
                            if (!e.Index.IsEmpty)
                            {
                                index = e.Index;
                                addedNode = node.Content.Reference.AsEnumerable[e.Index].TargetNode;
                            }
                            else
                            {
                                var reference = node.Content.Reference.AsEnumerable.First(x => x.TargetNode.Content.Retrieve() == e.NewValue);
                                index = reference.Index;
                                addedNode = reference.TargetNode;
                            }

                            if (addedNode != null)
                            {
                                var path = new GraphNodePath(node).PushIndex(index);
                                visitor.Visit(addedNode, path);
                            }
                        }
                        break;
                }
            }

            FinalizeChange?.Invoke(sender, new GraphContentChangeEventArgs(e));
        }
Example #48
0
 /// <summary>
 /// Indicates whether a node should be visited.
 /// </summary>
 /// <param name="node">The node to evaluate.</param>
 /// <param name="currentPath">The path of the node to evaluate.</param>
 /// <returns>True if the node should be visited, False otherwise.</returns>
 protected virtual bool ShouldVisitNode(IGraphNode node, GraphNodePath currentPath)
 {
     return(!visitedNodes.Contains(node) && (ShouldVisit?.Invoke(node, currentPath) ?? true));
 }
 /// <summary>
 /// Visits an <see cref="ObjectReference"/>.
 /// </summary>
 /// <param name="referencer">The node containing the reference to visit.</param>
 /// <param name="reference">The reference to visit.</param>
 /// <param name="targetPath">The path of the node targeted by this reference.</param>
 protected virtual void VisitReference(IGraphNode referencer, ObjectReference reference, GraphNodePath targetPath)
 {
     if (ShouldVisitNode(referencer.Content as MemberContent, reference.TargetNode))
     {
         VisitNode(reference.TargetNode, targetPath);
     }
 }
Example #50
0
 /// <summary>
 /// Indicates whether a node should be visited.
 /// </summary>
 /// <param name="node">The node to evaluate.</param>
 /// <param name="currentPath">The path of the node to evaluate.</param>
 /// <returns>True if the node should be visited, False otherwise.</returns>
 protected virtual bool ShouldVisitNode(IGraphNode node, GraphNodePath currentPath)
 {
     return(!visitedNodes.Contains(node));
 }
Example #51
0
 private GraphNodePath Clone(IGraphNode newRoot, bool newTargetIsRootNode)
 {
     var clone = new GraphNodePath(newRoot, newTargetIsRootNode);
     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="memberContent">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(IContentNode node, MemberContent memberContent = null, GraphNodePath initialPath = null)
        {
            var path = initialPath ?? new GraphNodePath(node);

            RootNode = node;
            if (ShouldVisitNode(memberContent, node))
            {
                VisitNode(node, path);
            }
            RootNode = null;
        }
Example #53
0
 /// <summary>
 /// Visits an <see cref="ObjectReference"/>.
 /// </summary>
 /// <param name="referencer">The node containing the reference to visit.</param>
 /// <param name="reference">The reference to visit.</param>
 /// <param name="targetPath">The path of the node targeted by this reference.</param>
 protected virtual void VisitReference(IGraphNode referencer, ObjectReference reference, GraphNodePath targetPath)
 {
     if (ShouldVisitNode(reference.TargetNode, targetPath))
     {
         VisitNode(reference.TargetNode, targetPath);
     }
 }