示例#1
0
        protected override void ExecuteSync(IContentNode content, Index index, object parameter)
        {
            var value = content.Retrieve(index);
            var collectionDescriptor = (CollectionDescriptor)TypeDescriptorFactory.Default.Find(value.GetType());

            object itemToAdd;

            // First, check if parameter is an AbstractNodeEntry
            var abstractNodeEntry = parameter as AbstractNodeEntry;

            if (abstractNodeEntry != null)
            {
                itemToAdd = abstractNodeEntry.GenerateValue(null);
            }
            // Otherwise, assume it's an object
            else
            {
                var elementType = collectionDescriptor.ElementType;
                itemToAdd = parameter ?? (IsReferenceType(elementType) ? null : ObjectFactoryRegistry.NewInstance(elementType));
            }

            if (index.IsEmpty)
            {
                content.Add(itemToAdd);
            }
            else
            {
                // Handle collections in collections
                // TODO: this is not working on the observable node side
                var collectionNode = content.ItemReferences[index].TargetNode;
                collectionNode.Add(itemToAdd);
            }
        }
示例#2
0
        protected override ObjectReference FindTargetReference(IContentNode sourceNode, IContentNode targetNode, ObjectReference sourceReference)
        {
            if (sourceReference.Index.IsEmpty)
            {
                return(targetNode.TargetReference);
            }

            // Special case for objects that are identifiable: the object must be linked to the base only if it has the same id
            if (sourceReference.ObjectValue != null)
            {
                if (sourceReference.Index.IsEmpty)
                {
                    return(targetNode.TargetReference);
                }

                var sourceAssetNode = (IAssetNode)sourceNode;
                if ((sourceAssetNode as AssetMemberNode)?.IsNonIdentifiableCollectionContent ?? false)
                {
                    return(null);
                }

                // Enumerable reference: we look for an object with the same id
                var targetReference = targetNode.ItemReferences;
                var sourceIds       = CollectionItemIdHelper.GetCollectionItemIds(sourceNode.Retrieve());
                var targetIds       = CollectionItemIdHelper.GetCollectionItemIds(targetNode.Retrieve());
                var itemId          = sourceIds[sourceReference.Index.Value];
                var targetKey       = targetIds.GetKey(itemId);
                return(targetReference.FirstOrDefault(x => Equals(x.Index.Value, targetKey)));
            }

            // Not identifiable - default applies
            return(base.FindTargetReference(sourceNode, targetNode, sourceReference));
        }
示例#3
0
        internal void Refresh(IContentNode ownerNode, NodeContainer nodeContainer, Index index)
        {
            var objectValue = ownerNode.Retrieve(index);

            var boxedTarget = TargetNode as BoxedContent;

            if (boxedTarget != null && objectValue?.GetType() == TargetNode.Type)
            {
                // If we are boxing a struct, and the targeted type didn't change, we reuse the same nodes and just overwrite the struct value.
                boxedTarget.UpdateFromOwner(objectValue);
                // But we still need to refresh inner references!
                foreach (var member in TargetNode.Members.Where(x => x.IsReference))
                {
                    nodeContainer?.UpdateReferences(member);
                }
            }
            else if (TargetNode?.Value != objectValue)
            {
                // This call will recursively update the references.
                var target = SetTarget(objectValue, nodeContainer);
                if (target != null)
                {
                    var boxedContent = target as BoxedContent;
                    boxedContent?.SetOwnerContent(ownerNode, index);
                }
            }
            // This reference is not orphan anymore.
            orphanObject = null;
        }
示例#4
0
        /// <summary>
        /// Tests the validity of a node that is a member of an object.
        /// </summary>
        /// <param name="containerNode">The node of the container of this member.</param>
        /// <param name="memberNode">The memeber node to validate.</param>
        /// <param name="container">The value represented by the container node.</param>
        /// <param name="member">The value of the member represented by the member node.</param>
        /// <param name="memberName">The name of the member to validate.</param>
        /// <param name="isReference">Indicate whether the member node is expected to contain a reference to the value it represents.</param>
        public static void TestMemberNode(IContentNode containerNode, IContentNode memberNode, object container, object member, string memberName, bool isReference)
        {
            if (containerNode == null)
            {
                throw new ArgumentNullException(nameof(containerNode));
            }
            if (memberNode == null)
            {
                throw new ArgumentNullException(nameof(memberNode));
            }
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }

            // Check that the content is of the expected type.
            Assert.AreEqual(typeof(MemberContent), memberNode.GetType());
            // A node with a MemberContent should have the same name that the member in the container.
            Assert.AreEqual(memberName, ((IMemberNode)memberNode).Name);
            // A node with a MemberContent should have its container as parent.
            Assert.AreEqual(containerNode, ((IMemberNode)memberNode).Parent);
            // A node with a MemberContent should have the member value as value of its content.
            Assert.AreEqual(member, memberNode.Retrieve());
            // A node with a primitive MemberContent should not contain a reference.
            Assert.AreEqual(isReference, memberNode.IsReference);
        }
示例#5
0
        /// <summary>
        /// Tests the validity of a node that is an object that is a collection
        /// </summary>
        /// <param name="node">The node to validate.</param>
        /// <param name="obj">The value represented by this node.</param>
        /// <param name="isReference">Indicate whether the node is expected to contain an enumerable reference to the collection items.</param>
        public static void TestCollectionObjectContentNode(IContentNode node, object obj, bool isReference)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }

            // Check that the content is of the expected type.
            Assert.IsInstanceOf <ObjectContent>(node);
            // A node with an ObjectContent should have the related object as value of its content.
            Assert.AreEqual(obj, node.Retrieve());
            if (isReference)
            {
                // A node with an ObjectContent representing a collection of reference types should contain an enumerable reference.
                Assert.AreEqual(true, node.IsReference);
                Assert.Null(node.TargetReference);
                Assert.NotNull(node.ItemReferences);
            }
            else
            {
                // A node with an ObjectContent representing a collection of primitive or struct types should not contain a refernce.
                Assert.AreEqual(false, node.IsReference);
            }
            // A node with an ObjectContent representing a collection should not have any child.
            Assert.AreEqual(0, ((IObjectNode)node).Members.Count);
        }
示例#6
0
 protected static bool IsIndexExisting(IContentNode node, Index index)
 {
     if (node.IsReference)
     {
         var reference = node.ItemReferences;
         if (reference?.HasIndex(index) ?? false)
         {
             return(true);
         }
     }
     else
     {
         var value = node.Retrieve();
         var collectionDescriptor = node.Descriptor as CollectionDescriptor;
         if (collectionDescriptor != null && index.IsInt && index.Int >= 0 && index.Int < collectionDescriptor.GetCollectionCount(value))
         {
             return(true);
         }
         var dictionaryDescriptor = node.Descriptor as DictionaryDescriptor;
         if (dictionaryDescriptor != null && dictionaryDescriptor.KeyType.IsInstanceOfType(index.Value) && dictionaryDescriptor.ContainsKey(value, index.Value))
         {
             return(true);
         }
     }
     return(false);
 }
 private static void AssertCollection(IContentNode content, params string[] items)
 {
     for (var i = 0; i < items.Length; i++)
     {
         var item = items[i];
         Assert.AreEqual(item, content.Retrieve(new Index(i)));
     }
 }
示例#8
0
        protected override void ExecuteSync(IContentNode content, Index index, object parameter)
        {
            var indices     = (Tuple <int, int>)parameter;
            var sourceIndex = new Index(indices.Item1);
            var targetIndex = new Index(indices.Item2);
            var value       = content.Retrieve(sourceIndex);

            content.Remove(value, sourceIndex);
            content.Add(value, targetIndex);
        }
示例#9
0
        protected override void ExecuteSync(IContentNode content, Index index, object parameter)
        {
            var oldName       = index;
            var renamedObject = content.Retrieve(oldName);

            content.Remove(renamedObject, oldName);
            var newName = AddPrimitiveKeyCommand.GenerateStringKey(content.Value, content.Descriptor, (string)parameter);

            content.Add(renamedObject, newName);
        }
示例#10
0
        /// <summary>
        /// Sets the value of the model content associated to this <see cref="GraphNodeViewModel"/>. The value is actually modified only if the new value is different from the previous value.
        /// </summary>
        /// <returns><c>True</c> if the value has been modified, <c>false</c> otherwise.</returns>
        protected virtual bool SetModelContentValue(IContentNode node, object newValue)
        {
            var oldValue = node.Retrieve(Index);

            if (!Equals(oldValue, newValue))
            {
                node.Update(newValue, Index);
                return(true);
            }
            return(false);
        }
        protected override void ExecuteSync(IContentNode content, Index index, object parameter)
        {
            var    value = content.Retrieve(index);
            var    dictionaryDescriptor = (DictionaryDescriptor)TypeDescriptorFactory.Default.Find(value.GetType());
            var    newKey  = dictionaryDescriptor.KeyType != typeof(string) ? new Index(Activator.CreateInstance(dictionaryDescriptor.KeyType)) : GenerateStringKey(value, dictionaryDescriptor, parameter as string);
            object newItem = null;

            if (!IsReferenceType(dictionaryDescriptor.ValueType))
            {
                newItem = CreateInstance(dictionaryDescriptor.ValueType);
            }
            content.Add(newItem, newKey);
        }
 private static void VerifyListenerEvent(MemberNodeChangeEventArgs e, IContentNode contentOwner, ContentChangeType type, Index index, object oldValue, object newValue, bool changeApplied)
 {
     Assert.NotNull(e);
     Assert.NotNull(contentOwner);
     Assert.AreEqual(type, e.ChangeType);
     Assert.AreEqual(contentOwner, e.Member);
     Assert.AreEqual(index, e.Index);
     Assert.AreEqual(newValue, e.NewValue);
     Assert.AreEqual(oldValue, e.OldValue);
     if (type == ContentChangeType.ValueChange)
     {
         Assert.AreEqual(changeApplied ? newValue : oldValue, contentOwner.Retrieve(index));
     }
 }
示例#13
0
        public override Task Execute(IContentNode content, Index index, object parameter)
        {
            var hasIndex     = content.Indices == null || content.Indices.Contains(index);
            var currentValue = hasIndex ? content.Retrieve(index) : (content.Type.IsValueType ? Activator.CreateInstance(content.Type) : null);
            var newValue     = ChangeValue(currentValue, parameter);

            if (hasIndex)
            {
                if (!Equals(newValue, currentValue))
                {
                    content.Update(newValue, index);
                }
            }
            else
            {
                content.Add(newValue, index);
            }
            return(Task.FromResult(0));
        }
示例#14
0
        /// <summary>
        /// Tests the validity of a node that is an object that is not a collection
        /// </summary>
        /// <param name="node">The node to validate.</param>
        /// <param name="obj">The value represented by this node.</param>
        /// <param name="childCount">The number of members expected in the node.</param>
        public static void TestNonCollectionObjectNode(IContentNode node, object obj, int childCount)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }

            // Check that the content is of the expected type.
            Assert.IsInstanceOf <ObjectContent>(node);
            // A node with an ObjectContent should have the related object as value of its content.
            Assert.AreEqual(obj, node.Retrieve());
            // A node with an ObjectContent should not contain a reference if it does not represent a collection.
            Assert.AreEqual(false, node.IsReference);
            // Check that we have the expected number of children.
            Assert.AreEqual(childCount, ((IObjectNode)node).Members.Count);
        }
示例#15
0
        protected override void ExecuteSync(IContentNode content, Index index, object parameter)
        {
            var item = content.Retrieve(index);

            content.Remove(item, index);
        }
示例#16
0
        public void Refresh(IContentNode ownerNode, NodeContainer nodeContainer)
        {
            var newObjectValue = ownerNode.Value;

            if (!(newObjectValue is IEnumerable))
            {
                throw new ArgumentException(@"The object is not an IEnumerable", nameof(newObjectValue));
            }

            ObjectValue = newObjectValue;

            var newReferences = new HybridDictionary <Index, ObjectReference>();

            if (IsDictionary)
            {
                foreach (var item in (IEnumerable)ObjectValue)
                {
                    var key   = GetKey(item);
                    var value = (ObjectReference)Reference.CreateReference(GetValue(item), ElementType, key);
                    newReferences.Add(key, value);
                }
            }
            else
            {
                var i = 0;
                foreach (var item in (IEnumerable)ObjectValue)
                {
                    var key   = new Index(i);
                    var value = (ObjectReference)Reference.CreateReference(item, ElementType, key);
                    newReferences.Add(key, value);
                    ++i;
                }
            }

            // The reference need to be updated if it has never been initialized, if the number of items is different, or if any index or any value is different.
            var needUpdate = items == null || newReferences.Count != items.Count || !AreItemsEqual(items, newReferences);

            if (needUpdate)
            {
                // We create a mapping values of the old list of references to their corresponding target node. We use a list because we can have multiple times the same target in items.
                var oldReferenceMapping = new List <KeyValuePair <object, ObjectReference> >();
                if (items != null)
                {
                    var existingIndices = ContentNode.GetIndices(ownerNode).ToList();
                    foreach (var item in items)
                    {
                        var boxedTarget = item.Value.TargetNode as BoxedContent;
                        // For collection of struct, we need to update the target nodes first so equity comparer will work. Careful tho, we need to skip removed items!
                        if (boxedTarget != null && existingIndices.Contains(item.Key))
                        {
                            // If we are boxing a struct, we reuse the same nodes if they are type-compatible and just overwrite the struct value.
                            var value = ownerNode.Retrieve(item.Key);
                            if (value?.GetType() == item.Value.TargetNode?.Type)
                            {
                                boxedTarget.UpdateFromOwner(ownerNode.Retrieve(item.Key));
                            }
                        }
                        if (item.Value.ObjectValue != null)
                        {
                            oldReferenceMapping.Add(new KeyValuePair <object, ObjectReference>(item.Value.ObjectValue, item.Value));
                        }
                    }
                }

                foreach (var newReference in newReferences)
                {
                    if (newReference.Value.ObjectValue != null)
                    {
                        var found = false;
                        var i     = 0;
                        foreach (var item in oldReferenceMapping)
                        {
                            if (Equals(newReference.Value.ObjectValue, item.Key))
                            {
                                // If this value was already present in the old list of reference, just use the same target node in the new list.
                                newReference.Value.SetTarget(item.Value.TargetNode);
                                // Remove consumed existing reference so if there is a second entry with the same "key", it will be the other reference that will be used.
                                oldReferenceMapping.RemoveAt(i);
                                found = true;
                                break;
                            }
                            ++i;
                        }
                        if (!found)
                        {
                            // Otherwise, do a full update that will properly initialize the new reference.
                            newReference.Value.Refresh(ownerNode, nodeContainer, newReference.Key);
                        }
                    }
                }
                items = newReferences;
                // Remark: this works because both KeyCollection and List implements IReadOnlyCollection. Any internal change to HybridDictionary might break this!
                Indices = (IReadOnlyCollection <Index>)newReferences.Keys;
            }
        }
示例#17
0
 /// <summary>
 /// Retrieve the value of the model content associated to this <see cref="GraphNodeViewModel"/>.
 /// </summary>
 /// <returns>The value of the model content associated to this <see cref="GraphNodeViewModel"/>.</returns>
 protected object GetModelContentValue()
 {
     return(SourceNode.Retrieve(Index));
 }