예제 #1
0
        public override ObjectReference FindTargetReference(IGraphNode sourceNode, IGraphNode targetNode, ObjectReference sourceReference)
        {
            // Not identifiable - default applies
            if (sourceReference.Index.IsEmpty || sourceReference.ObjectValue == null)
            {
                return(base.FindTargetReference(sourceNode, targetNode, sourceReference));
            }

            // Special case for objects that are identifiable: the object must be linked to the base only if it has the same id
            var sourceAssetNode = (AssetObjectNode)sourceNode;
            var targetAssetNode = (AssetObjectNode)targetNode;

            if (!CollectionItemIdHelper.HasCollectionItemIds(sourceAssetNode.Retrieve()))
            {
                return(null);
            }

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

            foreach (var targetRef in targetReference)
            {
                if (Equals(targetRef.Index.Value, targetKey))
                {
                    return(targetRef);
                }
            }

            return(null);
        }
예제 #2
0
        private bool ShouldGenerateItemIdCollection(object collection)
        {
            // Do not generate for value types (collections that are struct) or null
            if (collection?.GetType().IsValueType != false)
            {
                return(false);
            }

            // Do not generate if within a type that doesn't use identifiable collections
            if (inNonIdentifiableType > 0)
            {
                return(false);
            }

            // Do not generate if item id collection already exists
            if (CollectionItemIdHelper.HasCollectionItemIds(collection))
            {
                return(false);
            }

            // Do not generate if the collection has been flagged to not be identifiable
            if (nonIdentifiableCollection?.Contains(collection) == true)
            {
                return(false);
            }

            return(true);
        }
예제 #3
0
        /// <inheritdoc/>
        protected override void VisitObjectNode([NotNull] IAssetObjectNode objectNode, int inNonIdentifiableType)
        {
            if (!objectNode.IsReference)
            {
                return;
            }

            foreach (var index in ((IAssetObjectNodeInternal)objectNode).Indices)
            {
                if (!propertyGraphDefinition.IsTargetItemObjectReference(objectNode, index, objectNode.Retrieve(index)))
                {
                    continue;
                }

                var itemPath = ConvertPath(CurrentPath, inNonIdentifiableType);
                if (CollectionItemIdHelper.HasCollectionItemIds(objectNode.Retrieve()))
                {
                    var itemId = objectNode.IndexToId(index);
                    itemPath.PushItemId(itemId);
                }
                else
                {
                    itemPath.PushIndex(index.Value);
                }
                var value = objectNode.Retrieve(index) as IIdentifiable;
                if (value == null)
                {
                    throw new InvalidOperationException("IsObjectReference returned true for an object that is not IIdentifiable");
                }
                var id = value.Id;
                if (ShouldOutputReference?.Invoke(id) ?? true)
                {
                    Result.Set(itemPath, id);
                }
            }
        }
예제 #4
0
        internal void OnItemChanged(object sender, ItemChangeEventArgs e)
        {
            var value = node.Retrieve();

            if (!CollectionItemIdHelper.HasCollectionItemIds(value))
            {
                return;
            }

            // Make sure that we have item ids everywhere we're supposed to.
            AssetCollectionItemIdHelper.GenerateMissingItemIds(e.Collection.Retrieve());

            // Clear the cached item identifier collection.
            collectionItemIdentifiers = null;

            // Create new ids for collection items
            var baseNode             = (AssetObjectNode)BaseNode;
            var removedId            = ItemId.Empty;
            var isOverriding         = baseNode != null && !PropertyGraph.UpdatingPropertyFromBase;
            var itemIds              = CollectionItemIdHelper.GetCollectionItemIds(value);
            var collectionDescriptor = node.Descriptor as CollectionDescriptor;

            switch (e.ChangeType)
            {
            case ContentChangeType.CollectionUpdate:
                break;

            case ContentChangeType.CollectionAdd:
            {
                // Compute the id we will add for this item
                var itemId = restoringId != ItemId.Empty ? restoringId : ItemId.New();
                // Add the id to the proper location (insert or add)
                if (collectionDescriptor != null)
                {
                    if (e.Index == Index.Empty)
                    {
                        throw new InvalidOperationException("An item has been added to a collection that does not have a predictable Add. Consider using NonIdentifiableCollectionItemsAttribute on this collection.");
                    }

                    itemIds.Insert(e.Index.Int, itemId);
                }
                else
                {
                    itemIds[e.Index.Value] = itemId;
                }
                break;
            }

            case ContentChangeType.CollectionRemove:
            {
                var itemId = itemIds[e.Index.Value];
                // update isOverriding, it should be true only if the item being removed exist in the base.
                isOverriding = isOverriding && baseNode.HasId(itemId);
                removedId    = collectionDescriptor != null?itemIds.DeleteAndShift(e.Index.Int, isOverriding) : itemIds.Delete(e.Index.Value, isOverriding);

                break;
            }

            default:
                throw new ArgumentOutOfRangeException();
            }


            // Don't update override if propagation from base is disabled.
            if (PropertyGraph?.Container?.PropagateChangesFromBase == false)
            {
                return;
            }

            // Mark it as New if it does not come from the base
            if (!ResettingOverride)
            {
                if (e.ChangeType != ContentChangeType.CollectionRemove && isOverriding)
                {
                    // If it's an add or an updating, there is no scenario where we can be "un-overriding" without ResettingOverride, so we pass true.
                    OverrideItem(true, e.Index);
                }
                else if (e.ChangeType == ContentChangeType.CollectionRemove)
                {
                    // If it's a delete, it could be an item that was previously added as an override, and that should not be marked as "deleted-overridden", so we pass isOverriding
                    OverrideDeletedItem(isOverriding, removedId);
                }
            }
        }
        public static YamlAssetPath ConvertPath([NotNull] GraphNodePath path, int inNonIdentifiableType = 0)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            var currentNode = (IAssetNode)path.RootNode;
            var result      = new YamlAssetPath();
            var i           = 0;

            foreach (var item in path.Path)
            {
                switch (item.Type)
                {
                case GraphNodePath.ElementType.Member:
                {
                    var member = item.Name;
                    result.PushMember(member);
                    var objectNode = currentNode as IObjectNode;
                    if (objectNode == null)
                    {
                        throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                    }
                    currentNode = (IAssetNode)objectNode.TryGetChild(member);
                    break;
                }

                case GraphNodePath.ElementType.Target:
                {
                    if (i < path.Path.Count - 1)
                    {
                        var targetingMemberNode = currentNode as IMemberNode;
                        if (targetingMemberNode == null)
                        {
                            throw new InvalidOperationException($"An IMemberNode was expected when processing the path [{path}]");
                        }
                        currentNode = (IAssetNode)targetingMemberNode.Target;
                    }
                    break;
                }

                case GraphNodePath.ElementType.Index:
                {
                    var index      = item.Index;
                    var objectNode = currentNode as AssetObjectNode;
                    if (objectNode == null)
                    {
                        throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                    }
                    if (inNonIdentifiableType > 0 || !CollectionItemIdHelper.HasCollectionItemIds(objectNode.Retrieve()))
                    {
                        result.PushIndex(index.Value);
                    }
                    else
                    {
                        var id = objectNode.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 = (IAssetNode)objectNode.IndexedTarget(index);
                    }
                    break;
                }

                default:
                    throw new ArgumentOutOfRangeException();
                }
                ++i;
            }
            return(result);
        }