Example #1
0
        /// <summary>
        /// Clones a sub-hierarchy of a composite hierarchical asset.
        /// </summary>
        /// <param name="sourceNodeContainer">The container in which are the nodes of the hierarchy to clone, used to extract metadata (overrides, etc.) if needed.</param>
        /// <param name="targetNodeContainer">The container in which the nodes of the cloned hierarchy should be created, used to re-apply metadata (overrides, etc.) if needed.</param>
        /// <param name="asset">The asset from which to clone sub-hierarchies.</param>
        /// <param name="sourceRootIds">The ids that are the roots of the sub-hierarchies to clone.</param>
        /// <param name="flags">The flags customizing the cloning operation.</param>
        /// <param name="idRemapping">A dictionary containing the remapping of <see cref="IIdentifiable.Id"/> if <see cref="AssetClonerFlags.GenerateNewIdsForIdentifiableObjects"/> has been passed to the cloner.</param>
        /// <returns>A <see cref="AssetCompositeHierarchyData{TAssetPartDesign, TAssetPart}"/> corresponding to the cloned parts.</returns>
        /// <remarks>The parts passed to this methods must be independent in the hierarchy.</remarks>
        public static AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> CloneSubHierarchies([NotNull] AssetNodeContainer sourceNodeContainer, [NotNull] AssetNodeContainer targetNodeContainer,
                                                                                                     [NotNull] AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> asset, [NotNull] IEnumerable <Guid> sourceRootIds, SubHierarchyCloneFlags flags, [NotNull] out Dictionary <Guid, Guid> idRemapping)
        {
            if (sourceNodeContainer == null)
            {
                throw new ArgumentNullException(nameof(sourceNodeContainer));
            }
            if (targetNodeContainer == null)
            {
                throw new ArgumentNullException(nameof(targetNodeContainer));
            }
            if (asset == null)
            {
                throw new ArgumentNullException(nameof(asset));
            }
            if (sourceRootIds == null)
            {
                throw new ArgumentNullException(nameof(sourceRootIds));
            }

            // Extract the actual sub hierarchies to clone from the asset into a new instance of AssetCompositeHierarchyData
            var subTreeHierarchy = new AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart>();

            foreach (var rootId in sourceRootIds)
            {
                if (!asset.Hierarchy.Parts.ContainsKey(rootId))
                {
                    throw new ArgumentException(@"The source root parts must be parts of this asset.", nameof(sourceRootIds));
                }

                subTreeHierarchy.RootParts.Add(asset.Hierarchy.Parts[rootId].Part);

                subTreeHierarchy.Parts.Add(asset.Hierarchy.Parts[rootId]);
                foreach (var subTreePart in asset.EnumerateChildParts(asset.Hierarchy.Parts[rootId].Part, true))
                {
                    subTreeHierarchy.Parts.Add(asset.Hierarchy.Parts[subTreePart.Id]);
                }
            }

            var assetType = asset.GetType();

            // Create a new empty asset of the same type, and assign the sub hierachies to clone to it
            var cloneAsset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)Activator.CreateInstance(assetType);

            cloneAsset.Hierarchy = subTreeHierarchy;
            var assetDefinition = AssetQuantumRegistry.GetDefinition(assetType);

            // We get the node corresponding to the new asset in the source NodeContainer, to be able to generate metadata (overrides, object references) needed for cloning.
            var rootNode           = sourceNodeContainer.GetOrCreateNode(cloneAsset);
            var externalReferences = ExternalReferenceCollector.GetExternalReferences(assetDefinition, rootNode);
            var overrides          = (flags & SubHierarchyCloneFlags.RemoveOverrides) == 0 ? GenerateOverridesForSerialization(rootNode) : null;

            // Now we ready to clone, let's just translate the flags and pass everything to the asset cloner.
            var clonerFlags = AssetClonerFlags.None;

            if ((flags & SubHierarchyCloneFlags.GenerateNewIdsForIdentifiableObjects) != 0)
            {
                clonerFlags |= AssetClonerFlags.GenerateNewIdsForIdentifiableObjects;
            }
            if ((flags & SubHierarchyCloneFlags.CleanExternalReferences) != 0)
            {
                clonerFlags |= AssetClonerFlags.ClearExternalReferences;
            }
            // We don't need to clone the asset itself, just the hierarchy. The asset itself is just useful so the property graph is in a normal context to do what we need.
            var clonedHierarchy = AssetCloner.Clone(subTreeHierarchy, clonerFlags, externalReferences, out idRemapping);

            if ((flags & SubHierarchyCloneFlags.RemoveOverrides) == 0)
            {
                // We need to propagate the override information to the nodes of the cloned objects into the target node container.
                // Let's reuse our temporary asset, and get its node in the target node container.
                rootNode = targetNodeContainer.GetOrCreateNode(cloneAsset);
                // Replace the initial hierarchy by the cloned one (through the Update method, in case the target container is the same as the source one).
                rootNode[nameof(AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> .Hierarchy)].Update(clonedHierarchy);
                // Remap the paths to overriden properties in case we generated new ids for identifiable objects.
                AssetCloningHelper.RemapIdentifiablePaths(overrides, idRemapping);
                // Finally apply the overrides that come from the source parts.
                ApplyOverrides((IAssetNode)rootNode, overrides);
            }

            return(clonedHierarchy);
        }
Example #2
0
 /// <summary>
 /// Clones a sub-hierarchy of a composite hierarchical asset.
 /// </summary>
 /// <param name="nodeContainer">The container in which are the nodes of the hierarchy to clone and in which to create nodes for the cloned hierarchy, used to propagate metadata (overrides, etc.) if needed.</param>
 /// <param name="asset">The asset from which to clone sub-hierarchies.</param>
 /// <param name="sourceRootIds">The ids that are the roots of the sub-hierarchies to clone.</param>
 /// <param name="flags">The flags customizing the cloning operation.</param>
 /// <param name="idRemapping">A dictionary containing the remapping of <see cref="IIdentifiable.Id"/> if <see cref="AssetClonerFlags.GenerateNewIdsForIdentifiableObjects"/> has been passed to the cloner.</param>
 /// <returns>A <see cref="AssetCompositeHierarchyData{TAssetPartDesign, TAssetPart}"/> corresponding to the cloned parts.</returns>
 /// <remarks>The parts passed to this methods must be independent in the hierarchy.</remarks>
 public static AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> CloneSubHierarchies([NotNull] AssetNodeContainer nodeContainer, [NotNull] AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> asset,
                                                                                              [NotNull] IEnumerable <Guid> sourceRootIds, SubHierarchyCloneFlags flags, [NotNull] out Dictionary <Guid, Guid> idRemapping)
 {
     return(CloneSubHierarchies(nodeContainer, nodeContainer, asset, sourceRootIds, flags, out idRemapping));
 }