/// <inheritdoc/> protected override object TransformForSerialization(ITypeDescriptor descriptor, object collection) { var dictionaryDescriptor = (DictionaryDescriptor)descriptor; var instance = CreatEmptyContainer(descriptor); CollectionItemIdentifiers identifier; if (!CollectionItemIdHelper.TryGetCollectionItemIds(collection, out identifier)) { identifier = new CollectionItemIdentifiers(); } var keyWithIdType = typeof(KeyWithId <>).MakeGenericType(dictionaryDescriptor.KeyType); foreach (var item in dictionaryDescriptor.GetEnumerator(collection)) { ItemId id; if (!identifier.TryGet(item.Key, out id)) { id = ItemId.New(); identifier.Add(item.Key, id); } var keyWithId = Activator.CreateInstance(keyWithIdType, id, item.Key); instance.Add(keyWithId, item.Value); } return(instance); }
/// <inheritdoc/> protected override object TransformForSerialization(ITypeDescriptor descriptor, object collection) { var instance = CreatEmptyContainer(descriptor); CollectionItemIdentifiers identifier; if (!CollectionItemIdHelper.TryGetCollectionItemIds(collection, out identifier)) { identifier = new CollectionItemIdentifiers(); } var i = 0; foreach (var item in (IEnumerable)collection) { ItemId id; if (!identifier.TryGet(i, out id)) { id = ItemId.New(); identifier.Add(i, id); } instance.Add(id, item); ++i; } return(instance); }
public void Restore(object restoredItem, ItemId id) { CollectionItemIdentifiers oldIds = null; CollectionItemIdentifiers ids; if (!IsNonIdentifiableCollectionContent && TryGetCollectionItemIds(Content.Retrieve(), out ids)) { // Remove the item from deleted ids if it was here. ids.UnmarkAsDeleted(id); // Get a clone of the CollectionItemIdentifiers before we add back the item. oldIds = new CollectionItemIdentifiers(); ids.CloneInto(oldIds, null); } // Actually restore the item. Content.Add(restoredItem); if (TryGetCollectionItemIds(Content.Retrieve(), out ids) && oldIds != null) { // Find the new id that has been generated by the Add var idToReplace = oldIds.FindMissingId(ids); if (idToReplace == ItemId.Empty) { throw new InvalidOperationException("No ItemId to replace has been generated."); } } }
/// <inheritdoc/> protected override object TransformForSerialization(ITypeDescriptor descriptor, object collection) { var dictionaryDescriptor = (DictionaryDescriptor)descriptor; var instance = CreatEmptyContainer(descriptor); CollectionItemIdentifiers identifier; if (!CollectionItemIdHelper.TryGetCollectionItemIds(collection, out identifier)) { identifier = new CollectionItemIdentifiers(); } var keyWithIdType = typeof(KeyWithId<>).MakeGenericType(dictionaryDescriptor.KeyType); foreach (var item in dictionaryDescriptor.GetEnumerator(collection)) { ItemId id; if (!identifier.TryGet(item.Key, out id)) { id = ItemId.New(); identifier.Add(item.Key, id); } var keyWithId = Activator.CreateInstance(keyWithIdType, id, item.Key); instance.Add(keyWithId, item.Value); } return instance; }
public AssetObjectNodeExtended([NotNull] IAssetObjectNodeInternal node) { this.node = node; contents = new Dictionary <string, IGraphNode>(); itemOverrides = new Dictionary <ItemId, OverrideType>(); keyOverrides = new Dictionary <ItemId, OverrideType>(); disconnectedDeletedIds = new HashSet <ItemId>(); collectionItemIdentifiers = null; restoringId = ItemId.Empty; PropertyGraph = null; BaseNode = null; ResettingOverride = false; }
private bool TryGetCollectionItemIds(object instance, out CollectionItemIdentifiers itemIds) { if (collectionItemIdentifiers != null) { itemIds = collectionItemIdentifiers; return(true); } var result = CollectionItemIdHelper.TryGetCollectionItemIds(instance, out collectionItemIdentifiers); itemIds = collectionItemIdentifiers; return(result); }
public static CollectionItemIdentifiers GetCollectionItemIds(object instance) { var shadow = ShadowObject.GetOrCreate(instance); object result; if (shadow.TryGetValue(CollectionItemIdKey, out result)) { return (CollectionItemIdentifiers)result; } var itemIds = new CollectionItemIdentifiers(); shadow.Add(CollectionItemIdKey, itemIds); return itemIds; }
public static bool TryGetCollectionItemIds(object instance, out CollectionItemIdentifiers itemIds) { var shadow = ShadowObject.Get(instance); if (shadow == null) { itemIds = null; return false; } object result; itemIds = shadow.TryGetValue(CollectionItemIdKey, out result) ? (CollectionItemIdentifiers)result : null; return result != null; }
public static CollectionItemIdentifiers GetCollectionItemIds(object instance) { var shadow = ShadowObject.GetOrCreate(instance); object result; if (shadow.TryGetValue(CollectionItemIdKey, out result)) { return((CollectionItemIdentifiers)result); } var itemIds = new CollectionItemIdentifiers(); shadow.Add(CollectionItemIdKey, itemIds); return(itemIds); }
public static bool TryGetCollectionItemIds(object instance, out CollectionItemIdentifiers itemIds) { var shadow = ShadowObject.Get(instance); if (shadow == null) { itemIds = null; return(false); } object result; itemIds = shadow.TryGetValue(CollectionItemIdKey, out result) ? (CollectionItemIdentifiers)result : null; return(result != null); }
/// <summary> /// Fixes up the <see cref="CollectionItemIdentifiers"/> of a collection by generating new ids if there are any duplicate. /// </summary> /// <param name="collection">The collection to fix up.</param> /// <remarks>This method doesn't handle collections in derived objects that will be desynchronized afterwards.</remarks> private void Fixup(object collection) { CollectionItemIdentifiers itemIds; if (CollectionItemIdHelper.TryGetCollectionItemIds(collection, out itemIds)) { var items = new HashSet<ItemId>(); var localCopy = new CollectionItemIdentifiers(); itemIds.CloneInto(localCopy, null); foreach (var id in localCopy) { if (!items.Add(id.Value)) { logger?.Warning($"Duplicate item identifier [{id.Value}] in collection {CurrentPath} of asset [{assetItem.Location}]. Generating a new identifier to remove the duplicate entry."); itemIds[id.Key] = ItemId.New(); } } } }
/// <summary> /// Fixes up the <see cref="CollectionItemIdentifiers"/> of a collection by generating new ids if there are any duplicate. /// </summary> /// <param name="collection">The collection to fix up.</param> /// <remarks>This method doesn't handle collections in derived objects that will be desynchronized afterwards.</remarks> private void Fixup(object collection) { CollectionItemIdentifiers itemIds; if (CollectionItemIdHelper.TryGetCollectionItemIds(collection, out itemIds)) { var items = new HashSet <ItemId>(); var localCopy = new CollectionItemIdentifiers(); itemIds.CloneInto(localCopy, null); foreach (var id in localCopy) { if (!items.Add(id.Value)) { logger?.Warning($"Duplicate item identifier [{id.Value}] in collection {CurrentPath} of asset [{assetItem.Location}]. Generating a new identifier to remove the duplicate entry."); itemIds[id.Key] = ItemId.New(); } } } }
private void ContentChanged(object sender, MemberNodeChangeEventArgs e) { // Make sure that we have item ids everywhere we're supposed to. AssetCollectionItemIdHelper.GenerateMissingItemIds(e.Member.Retrieve()); // Clear the cached item identifier collection. collectionItemIdentifiers = null; var node = (AssetMemberNode)e.Member; if (node.IsNonIdentifiableCollectionContent) { return; } // Create new ids for collection items var baseNode = (AssetMemberNode)BaseContent; var isOverriding = baseNode != null && !PropertyGraph.UpdatingPropertyFromBase; var removedId = ItemId.Empty; switch (e.ChangeType) { case ContentChangeType.ValueChange: case ContentChangeType.CollectionUpdate: break; case ContentChangeType.CollectionAdd: { var collectionDescriptor = e.Member.Descriptor as CollectionDescriptor; var itemIds = CollectionItemIdHelper.GetCollectionItemIds(e.Member.Retrieve()); // Compute the id we will add for this item ItemId itemId; if (baseNode != null && PropertyGraph.UpdatingPropertyFromBase) { var baseCollection = baseNode.Retrieve(); var baseIds = CollectionItemIdHelper.GetCollectionItemIds(baseCollection); itemId = itemIds.FindMissingId(baseIds); } else { 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) { itemIds.Insert(e.Index.Int, itemId); } else { throw new InvalidOperationException("An item has been added to a collection that does not have a predictable Add. Consider using NonIdentifiableCollectionItemsAttribute on this collection."); } } else { itemIds[e.Index.Value] = itemId; } } break; case ContentChangeType.CollectionRemove: { var collectionDescriptor = e.Member.Descriptor as CollectionDescriptor; if (collectionDescriptor != null) { var itemIds = CollectionItemIdHelper.GetCollectionItemIds(e.Member.Retrieve()); removedId = itemIds.DeleteAndShift(e.Index.Int, isOverriding); } else { var itemIds = CollectionItemIdHelper.GetCollectionItemIds(e.Member.Retrieve()); removedId = 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 (baseNode != null && !PropertyGraph.UpdatingPropertyFromBase && !ResettingOverride) { if (e.ChangeType != ContentChangeType.CollectionRemove) { if (e.Index == Index.Empty) { OverrideContent(!ResettingOverride); } else { OverrideItem(!ResettingOverride, e.Index); } } else { OverrideDeletedItem(true, removedId); } } }
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 void Restore(object restoredItem, ItemId id) { CollectionItemIdentifiers oldIds = null; CollectionItemIdentifiers ids; if (!IsNonIdentifiableCollectionContent && TryGetCollectionItemIds(Content.Retrieve(), out ids)) { // Remove the item from deleted ids if it was here. ids.UnmarkAsDeleted(id); // Get a clone of the CollectionItemIdentifiers before we add back the item. oldIds = new CollectionItemIdentifiers(); ids.CloneInto(oldIds, null); } // Actually restore the item. Content.Add(restoredItem); if (TryGetCollectionItemIds(Content.Retrieve(), out ids) && oldIds != null) { // Find the new id that has been generated by the Add var idToReplace = oldIds.FindMissingId(ids); if (idToReplace == ItemId.Empty) throw new InvalidOperationException("No ItemId to replace has been generated."); } }
public bool TryGetCollectionItemIds(object instance, out CollectionItemIdentifiers itemIds) { if (collectionItemIdentifiers != null) { itemIds = collectionItemIdentifiers; return true; } var result = CollectionItemIdHelper.TryGetCollectionItemIds(instance, out collectionItemIdentifiers); itemIds = collectionItemIdentifiers; return result; }
/// <inheritdoc/> protected override object TransformForSerialization(ITypeDescriptor descriptor, object collection) { var instance = CreatEmptyContainer(descriptor); CollectionItemIdentifiers identifier; if (!CollectionItemIdHelper.TryGetCollectionItemIds(collection, out identifier)) { identifier = new CollectionItemIdentifiers(); } var i = 0; foreach (var item in (IEnumerable)collection) { ItemId id; if (!identifier.TryGet(i, out id)) { id = ItemId.New(); identifier.Add(i, id); } instance.Add(id, item); ++i; } return instance; }