Пример #1
0
        /// <summary>
        /// Finds the best index (and parent) at which to insert a new part that is propagated after being added to one of the bases of this asset.
        /// </summary>
        /// <param name="baseAsset">The base asset for the part that has been added.</param>
        /// <param name="newBasePart">The new part that has been added to the base.</param>
        /// <param name="newBasePartParent">The parent part of the part that has been added to the base.</param>
        /// <param name="instanceId">The id of the instance for which we are looking for an index and parent.</param>
        /// <param name="instanceParent">The parent in which to insert the new instance part. If null, the new part will be inserted as root of the hierarchy.</param>
        /// <returns>The index at which to insert the new part in the instance, or a negative value if the part should be discarded.</returns>
        protected virtual int FindBestInsertIndex(AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> baseAsset, TAssetPartDesign newBasePart, TAssetPart newBasePartParent, Guid instanceId, out TAssetPartDesign instanceParent)
        {
            instanceParent = null;
            var insertIndex = -1;

            // First, let's find out where it is the best to insert this new part
            if (newBasePartParent == null)
            {
                // The part is a root, so we must place it according to its sibling (since no parent exists).
                var partIndex = baseAsset.Hierarchy.RootParts.IndexOf(x => x.Id == newBasePart.Part.Id);
                // Let's try to find a sibling in the parts preceding it, in order
                for (var i = partIndex - 1; i >= 0 && insertIndex < 0; --i)
                {
                    var sibling         = baseAsset.Hierarchy.Parts[baseAsset.Hierarchy.RootParts[i].Id];
                    var instanceSibling = Asset.Hierarchy.Parts.Values.FirstOrDefault(x => x.Base?.InstanceId == instanceId && x.Base?.BasePartId == sibling.Part.Id);
                    // This sibling still exists instance-side, let's get its parent.
                    if (instanceSibling != null)
                    {
                        // If the sibling itself has a parent instance-side, let's use the same parent and insert after it
                        // Otherwise the sibling is root, let's insert after it in the root parts
                        var parent = Asset.GetParent(instanceSibling.Part);
                        instanceParent = parent != null ? Asset.Hierarchy.Parts[parent.Id] : null;
                        insertIndex    = Asset.IndexOf(instanceSibling.Part) + 1;
                        break;
                    }
                }

                // Let's try to find a sibling in the parts following it, in order
                for (var i = partIndex + 1; i < baseAsset.Hierarchy.RootParts.Count && insertIndex < 0; ++i)
                {
                    var sibling         = baseAsset.Hierarchy.Parts[baseAsset.Hierarchy.RootParts[i].Id];
                    var instanceSibling = Asset.Hierarchy.Parts.Values.FirstOrDefault(x => x.Base?.InstanceId == instanceId && x.Base?.BasePartId == sibling.Part.Id);
                    // This sibling still exists instance-side, let's get its parent.
                    if (instanceSibling != null)
                    {
                        // If the sibling itself has a parent instance-side, let's use the same parent and insert after it
                        // Otherwise the sibling is root, let's insert after it in the root parts
                        var parent = Asset.GetParent(instanceSibling.Part);
                        instanceParent = parent != null ? Asset.Hierarchy.Parts[parent.Id] : null;
                        insertIndex    = Asset.IndexOf(instanceSibling.Part);
                        break;
                    }
                }
            }
            else
            {
                // The new part is not root, it has a parent.
                instanceParent = Asset.Hierarchy.Parts.Values.FirstOrDefault(x => x.Base?.InstanceId == instanceId && x.Base?.BasePartId == newBasePartParent.Id);

                // If the parent has been removed instance side, the hierarchy to the new part does not exist anymore. We can discard it
                if (instanceParent != null)
                {
                    var partIndex = baseAsset.IndexOf(newBasePart.Part);

                    // Let's try to find a sibling in the parts preceding it, in order
                    for (var i = partIndex - 1; i >= 0 && insertIndex < 0; --i)
                    {
                        var sibling         = baseAsset.GetChild(newBasePartParent, i);
                        var instanceSibling = Asset.Hierarchy.Parts.Values.FirstOrDefault(x => x.Base?.InstanceId == instanceId && x.Base?.BasePartId == sibling.Id);
                        // This sibling still exists instance-side, let's insert after it
                        if (instanceSibling != null)
                        {
                            insertIndex = i + 1;
                        }
                    }

                    // Let's try to find a sibling in the parts following it, in order
                    for (var i = partIndex + 1; i < baseAsset.GetChildCount(newBasePartParent) && insertIndex < 0; ++i)
                    {
                        var sibling         = baseAsset.GetChild(newBasePartParent, i);
                        var instanceSibling = Asset.Hierarchy.Parts.Values.FirstOrDefault(x => x.Base?.InstanceId == instanceId && x.Base?.BasePartId == sibling.Id);
                        // This sibling still exists instance-side, let's insert before it
                        if (instanceSibling != null)
                        {
                            insertIndex = i - 1;
                        }
                    }

                    // Default position is first index
                    if (insertIndex < 0)
                    {
                        insertIndex = 0;
                    }
                }
            }

            if (insertIndex < 0)
            {
                // We couldn't find any parent/sibling in the instance. Either the parent has been removed, in which case we'll discard the part,
                // or the base is a single part that has been moved around, and we'll rely on the last known common ancestor of this instance to re-insert it.
                var isAlone = Asset.Hierarchy.Parts.Values.All(x => x.Base?.InstanceId != instanceId);
                if (isAlone)
                {
                    Guid parentId;
                    if (instancesCommonAncestors.TryGetValue(instanceId, out parentId) && parentId != Guid.Empty)
                    {
                        // FIXME: instancesCommonAncestors should be synchronized with existing instances, i.e. if the instance has been compltely removed then the common ancestor should have been cleared.
                        if (Asset.Hierarchy.Parts.TryGetValue(parentId, out instanceParent))
                        {
                            insertIndex = 0;
                        }
                    }
                }
            }
            return(insertIndex);
        }