示例#1
0
 public MergeableNode(T content, MergePoint[] mergePoints, params MergeableNode <T>[] children)
     : this(content, mergePoints)
 {
     if (children != null)
     {
         Children = new MergeableNodeCollection <T>();
         Children.AddRange(children);
     }
 }
示例#2
0
 public MergeableNode(T content, MergePoint mergePoint0, MergePoint mergePoint1, MergePoint mergePoint2, params MergeableNode <T>[] children)
     : this(content, new[] { mergePoint0, mergePoint1, mergePoint2 })
 {
     if (children != null)
     {
         Children = new MergeableNodeCollection <T>();
         Children.AddRange(children);
     }
 }
示例#3
0
        //--------------------------------------------------------------
        #region Creation and Cleanup
        //--------------------------------------------------------------
        #endregion


        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        /// <summary>
        /// Merges a collection of nodes to an existing collection.
        /// </summary>
        /// <param name="targetNodes">
        /// The existing collection into which the additional nodes are merged.
        /// </param>
        /// <param name="additionalNodes">
        /// The new nodes that shall be added to <paramref name="targetNodes"/>.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="targetNodes"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="additionalNodes"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// Cannot merge nodes. <see cref="MergeableNode{T}.Content"/> of a
        /// <see cref="MergeableNode{T}"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="MergeException">
        /// Merge operations failed. Could not find merge points.
        /// </exception>
        public void Merge(MergeableNodeCollection <T> targetNodes, MergeableNodeCollection <T> additionalNodes)
        {
            if (targetNodes == null)
            {
                throw new ArgumentNullException(nameof(targetNodes));
            }
            if (additionalNodes == null)
            {
                throw new ArgumentNullException(nameof(additionalNodes));
            }

            foreach (var node in additionalNodes.ToArray())
            {
                Merge(targetNodes, node);
            }
        }
示例#4
0
        /// <summary>
        /// Finds the merge target node.
        /// </summary>
        /// <param name="nodes">The nodes.</param>
        /// <param name="target">The name of the target node.</param>
        /// <returns>
        /// The index of the target node. <c>-1</c> if the target node is not found.
        /// </returns>
        private static int FindTargetNode(MergeableNodeCollection <T> nodes, string target)
        {
            int index;
            var numberOfNodes = nodes.Count;

            for (index = 0; index < numberOfNodes; index++)
            {
                if (nodes[index].Content.Name == target)
                {
                    break;
                }
            }

            if (index == numberOfNodes)
            {
                // No match found.
                return(-1);
            }

            return(index);
        }
示例#5
0
        protected virtual void OnInsert(MergeableNodeCollection <T> existingNodes, MergeableNode <T> node, int index)
        {
            if (!CloneNodesOnMerge)
            {
                // Moving nodes - destroying the input collection:
                node.Parent?.Children?.Remove(node);   // First detach node from parent.
                existingNodes.Insert(index, node);
            }
            else
            {
                // Copying nodes - leaving the input collection intact.
                var copy = new MergeableNode <T>(node.Content);

                existingNodes.Insert(index, copy);

                // Process children
                if (node.Children != null && node.Children.Count > 0)
                {
                    EnsureChildren(copy);
                    Merge(copy.Children, node.Children);
                }
            }
        }
示例#6
0
        private void Merge(MergeableNodeCollection <T> targetNodes, MergeableNode <T> node)
        {
            if (node == null)
            {
                return;
            }

            if (node.Content == null)
            {
                throw new NotSupportedException("Cannot merge nodes. MergeableNode must not be empty (Content != null).");
            }

            if (node.MergePoints == null)
            {
                return;
            }

            foreach (var mergePoint in node.MergePoints)
            {
                string targetName     = mergePoint.Target;
                var    mergeOperation = mergePoint.Operation;

                if (mergeOperation == MergeOperation.Ignore)
                {
                    return;   // Ignore this node.
                }
                // Check whether node with the same action name already exists.
                int  indexOfExistingNode = FindTargetNode(targetNodes, node.Content.Name);
                bool nodeExists          = (indexOfExistingNode >= 0);

                int  indexOfTarget = -1;
                bool targetFound   = false;

                // Find target node.
                // (MergeOperation.Append and MergeOperation.Prepend do not need a target node.)
                if (!nodeExists && mergeOperation != MergeOperation.Append && mergeOperation != MergeOperation.Prepend)
                {
                    indexOfTarget = FindTargetNode(targetNodes, targetName);
                    targetFound   = (indexOfTarget >= 0);

                    if (!targetFound)
                    {
                        continue;       // Target not found. Try next merge point.
                    }
                }

                switch (mergeOperation)
                {
                case MergeOperation.Ignore:
                    // Do nothing.
                    Debug.Fail("We should never get here, cause all MergeOperation.Ignore are handled above.");
                    break;

                case MergeOperation.Match:
                    // Do not add this node, but merge children
                    Debug.Assert(nodeExists || targetFound, "Sanity check.");

                    if (nodeExists)
                    {
                        if (node.Children != null && node.Children.Count > 0)
                        {
                            var targetNode = targetNodes[indexOfExistingNode];
                            EnsureChildren(targetNode);
                            Merge(targetNode.Children, node.Children);
                        }
                    }
                    else
                    {
                        if (node.Children != null && node.Children.Count > 0)
                        {
                            var targetNode = targetNodes[indexOfTarget];
                            EnsureChildren(targetNode);
                            Merge(targetNode.Children, node.Children);
                        }
                    }
                    break;

                case MergeOperation.Prepend:
                    // Merge node with existing node, or prepend at the beginning.
                    if (nodeExists)
                    {
                        OnMerge(targetNodes[indexOfExistingNode], node);
                    }
                    else
                    {
                        OnInsert(targetNodes, node, 0);
                    }
                    break;

                case MergeOperation.Append:
                    // Merge node with existing node, or append at the end.
                    if (nodeExists)
                    {
                        OnMerge(targetNodes[indexOfExistingNode], node);
                    }
                    else
                    {
                        OnInsert(targetNodes, node, targetNodes.Count);
                    }
                    break;

                case MergeOperation.InsertBefore:
                    // Merge node with existing, or insert before merge point.
                    Debug.Assert(nodeExists || targetFound, "Sanity check.");
                    if (nodeExists)
                    {
                        OnMerge(targetNodes[indexOfExistingNode], node);
                    }
                    else
                    {
                        OnInsert(targetNodes, node, indexOfTarget);
                    }
                    break;

                case MergeOperation.InsertAfter:
                    // Merge node with existing or insert after merge point.
                    Debug.Assert(nodeExists || targetFound, "Sanity check.");
                    if (nodeExists)
                    {
                        OnMerge(targetNodes[indexOfExistingNode], node);
                    }
                    else
                    {
                        OnInsert(targetNodes, node, indexOfTarget + 1);
                    }
                    break;

                case MergeOperation.Replace:
                    // Replace existing node (or node at merge point).
                    Debug.Assert(nodeExists || targetFound, "Sanity check.");
                    if (nodeExists)
                    {
                        targetNodes.RemoveAt(indexOfExistingNode);
                        OnInsert(targetNodes, node, indexOfExistingNode);
                    }
                    else
                    {
                        targetNodes.RemoveAt(indexOfTarget);
                        OnInsert(targetNodes, node, indexOfTarget);
                    }
                    break;

                case MergeOperation.Remove:
                    // Remove existing node (or node at merge point)
                    Debug.Assert(nodeExists || targetFound, "Sanity check.");
                    if (nodeExists)
                    {
                        targetNodes.RemoveAt(indexOfExistingNode);
                    }
                    else
                    {
                        targetNodes.RemoveAt(indexOfTarget);
                    }
                    break;
                }
            }
        }