Пример #1
0
        private void Merge(List <IAction> previous, List <IAction> next)
        {
            if (previous == null)
            {
                return;
            }

            for (int i = previous.Count; i-- > 0;)
            {
                if (next.Count == 0)
                {
                    break;
                }

                IAction          action          = previous[i];
                IMergeableAction mergeableAction = action as IMergeableAction;

                if (mergeableAction == null)
                {
                    continue;
                }

                IAction mergedAction = mergeableAction.Merge(this, next);

                if (mergedAction == null)
                {
                    previous.RemoveAt(i);
                }
                else if (mergedAction != action)
                {
                    previous[i] = mergedAction;
                }
            }

            previous.AddRange(next);
        }
Пример #2
0
        /// <summary>
        /// Runs an action and puts it in the undo list.
        /// </summary>
        /// <param name="action">action to run</param>
        public void Run(IAction action)
        {
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            bool changed = false;

            recursion++;

            try
            {
                switch (state)
                {
                case UndoRedoManagerState.Idle:
                    changed       = InternalClearRedo();
                    state         = UndoRedoManagerState.ProcessDo;
                    current.prime = null;
                    current.list  = new List <IAction>();

                    break;

                case UndoRedoManagerState.ProcessDo:
                    break;

                default:
                    throw new InvalidOperationException();
                }

                ScopeAction scope = action as ScopeAction;

                if (action.Run(this, ActionType.Do))
                {
                    IAction item = action;

                    Merge(current.list, ref item);

                    if ((item != null) && !IsSecondary(item))
                    {
                        if ((current.prime == null) || (recursion == 1) && (scope == null))
                        {
                            current.prime = item;
                        }
                    }
                }

                if (recursion != 1)
                {
                    return;
                }

                if (current.prime == null)
                {
                    // There is no prime action.
                    // We can cancel whole action.
                    UndoCurrent();

                    return;
                }

                bool hasPrimary = false;

                for (int i = 0, c = current.list.Count; i < c; i++)
                {
                    IAction item = current.list[i];

                    if ((current.prime != item) && !IsSecondary(item))
                    {
                        hasPrimary = true;

                        break;
                    }
                }

                // End of scope.
                if (!hasPrimary && (scope != null))
                {
                    UndoCurrent();

                    return;
                }

                changed = true;

                bool addAction = true;

                if (!hasPrimary && (actions.Count != 0))
                {
                    // Merge previous action with a new one.
                    Action previousAction = actions[actions.Count - 1];

                    IMergeableAction mergeableAction = previousAction.prime as IMergeableAction;

                    if (mergeableAction != null)
                    {
                        IAction mergedAction;

                        mergeList.Add(current.prime);

                        try
                        {
                            mergedAction = mergeableAction.Merge(this, mergeList);
                            addAction    = mergeList.Count != 0;

                            int index = current.list.IndexOf(current.prime);

                            if (addAction)
                            {
                                current.prime = mergeList[0];

                                if (index != -1)
                                {
                                    current.list[index] = current.prime;
                                }
                            }
                            else
                            {
                                current.prime = mergedAction;
                                current.list.RemoveAt(index);
                            }
                        }
                        finally
                        {
                            mergeList.Clear();
                        }

                        if (!addAction)
                        {
                            if (previousAction.list != null)
                            {
                                Merge(previousAction.list, current.list);
                                current.list = previousAction.list;
                            }

                            if (current.prime == null)
                            {
                                UndoCurrent();
                                actions.RemoveAt(actions.Count - 1);
                            }
                            else
                            {
                                if (current.list.Count < 2)
                                {
                                    current.list = null;
                                }

                                actions[actions.Count - 1] = current;
                            }

                            return;
                        }
                    }
                }

                if (addAction)
                {
                    if (current.list.Count < 2)
                    {
                        current.list = null;
                    }

                    actions.Add(current);
                }
            }
            finally
            {
                if (--recursion == 0)
                {
                    state        = UndoRedoManagerState.Idle;
                    redoPosition = actions.Count;

                    if (CheckUndoListSize())
                    {
                        changed = true;
                    }

                    if (changed)
                    {
                        OnChanged();
                    }
                }
            }
        }