예제 #1
0
        /// <summary>
        /// This does two different things, depending on the MergeUndoTransactionPolicys in question.
        /// It either simply pushes the current transaction to the undo stack, OR it merges it with
        /// the most recent item in the stack.
        /// </summary>
        private void MergeOrPushToUndoStack(MockTextUndoTransaction transaction)
        {
            ITextUndoTransaction transactionAdded;
            TextUndoTransactionCompletionResult transactionResult;

            MockTextUndoTransaction utPrevious = _undoStack.Count > 0 ? _undoStack.Peek() as MockTextUndoTransaction : null;

            if (utPrevious != null && ProceedWithMerge(transaction, utPrevious))
            {
                // Temporarily make utPrevious non-read-only, during merge.
                utPrevious.IsReadOnly = false;
                try {
                    transaction.MergePolicy.PerformTransactionMerge(utPrevious, transaction);
                } finally {
                    utPrevious.IsReadOnly = true;
                }

                // utPrevious is already on the undo stack, so we don't need to add it; but report
                // it as the added transaction in the UndoTransactionCompleted event.
                transactionAdded  = utPrevious;
                transactionResult = TextUndoTransactionCompletionResult.TransactionMerged;
            }
            else
            {
                _undoStack.Push(transaction);

                transactionAdded  = transaction;
                transactionResult = TextUndoTransactionCompletionResult.TransactionAdded;
            }

            RaiseUndoTransactionCompleted(transactionAdded, transactionResult);
        }
예제 #2
0
        /// <summary>
        /// Creates a new transaction, nests it in the previously current transaction, and marks it current.
        /// If there is a redo stack, it gets cleared.
        /// UNDONE: should the redo-clearing happen now or when the new transaction is committed?
        /// </summary>
        /// <param name="description">A string description for the transaction.</param>
        /// <returns></returns>
        public ITextUndoTransaction CreateTransaction(string description)
        {
            description = description ?? string.Empty;

            // If there is a pending transaction that has already been completed, we should not be permitted
            // to open a new transaction, since it cannot later be added to its parent.
            if ((_currentTransaction != null) && (_currentTransaction.State != UndoTransactionState.Open))
            {
                throw new InvalidOperationException("Strings.CannotCreateTransactionWhenCurrentTransactionNotOpen");
            }

            // new transactions that are visible should clear the redo stack.
            if (_currentTransaction == null)
            {
                foreach (var textUndoTransaction in _redoStack)
                {
                    var redoTransaction = (MockTextUndoTransaction)textUndoTransaction;
                    redoTransaction.Invalidate();
                }

                _redoStack.Clear();
            }

            MockTextUndoTransaction newTransaction = new MockTextUndoTransaction(this, _currentTransaction, description);

            _currentTransaction = newTransaction;

            return(_currentTransaction);
        }
예제 #3
0
 /// <summary>
 /// Copies all of the primitives from the given transaction, and appends them to the UndoPrimitives list.
 /// </summary>
 /// <param name="transaction">The MockTextUndoTransaction to copy from.</param>
 public void CopyPrimitivesFrom(MockTextUndoTransaction transaction)
 {
     foreach (var p in transaction.UndoPrimitives)
     {
         AddUndo(p);
     }
 }
예제 #4
0
        private bool ProceedWithMerge(MockTextUndoTransaction transaction1, MockTextUndoTransaction transaction2)
        {
            MockTextUndoHistoryRegistry registry = UndoHistoryRegistry;

            return(transaction1.MergePolicy != null &&
                   transaction2.MergePolicy != null &&
                   transaction1.MergePolicy.TestCompatiblePolicy(transaction2.MergePolicy) &&
                   transaction1.MergePolicy.CanMerge(transaction1, transaction2));
        }
예제 #5
0
 public MockTextUndoHistory(MockTextUndoHistoryRegistry undoHistoryRegistry)
 {
     _currentTransaction           = null;
     UndoHistoryRegistry           = undoHistoryRegistry;
     _undoStack                    = new Stack <ITextUndoTransaction>();
     _redoStack                    = new Stack <ITextUndoTransaction>();
     _activeUndoOperationPrimitive = null;
     _state = TextUndoHistoryState.Idle;
 }
예제 #6
0
        public MockTextUndoTransaction(ITextUndoHistory history, ITextUndoTransaction parent, string description)
        {
            _history = history as MockTextUndoHistory;
            _parent = parent as MockTextUndoTransaction;

            Description = description;

            _state = UndoTransactionState.Open;
            _primitives = new List<ITextUndoPrimitive>();
            MergePolicy = NullMergeUndoTransactionPolicy.Instance;
            IsReadOnly = true;
        }
예제 #7
0
        /// <summary>
        /// This is how the transactions alert their containing history that they have finished
        /// (likely from the Dispose() method).
        /// </summary>
        /// <param name="transaction">This is the transaction that's finishing. It should match the history's current transaction.
        /// If it does not match, then the current transaction will be discarded and an exception will be thrown.</param>
        public void EndTransaction(ITextUndoTransaction transaction)
        {
            if (_currentTransaction != transaction)
            {
                _currentTransaction = null;
                throw new InvalidOperationException("Strings.EndTransactionOutOfOrder");
            }

            // only add completed transactions to their parents (or the stack)
            if (_currentTransaction.State == UndoTransactionState.Completed)
            {
                if (_currentTransaction.Parent == null) // stack bottomed out!
                {
                    MergeOrPushToUndoStack(_currentTransaction);
                }
            }

            _currentTransaction = _currentTransaction.Parent as MockTextUndoTransaction;
        }
예제 #8
0
        /// <summary>
        /// Performs a redo operation and places the primitives on the redo stack, up until (and
        /// including) the transaction indicated. This is called by the linked undo transaction that
        /// is aware of the linking relationship between transactions, and it does not call back into
        /// the transactions' public Redo().
        /// </summary>
        /// <param name="transaction"></param>
        public void RedoInIsolation(MockTextUndoTransaction transaction)
        {
            TextUndoHistoryState originalState = _state;

            _state = TextUndoHistoryState.Redoing;
            using (new AutoEnclose(delegate { this._state = originalState; })) {
                if (_redoStack.Contains(transaction))
                {
                    MockTextUndoTransaction redone = null;
                    while (redone != transaction)
                    {
                        MockTextUndoTransaction ut = _redoStack.Pop() as MockTextUndoTransaction;
                        ut.Do();
                        _undoStack.Push(ut);

                        RaiseUndoRedoHappened(_state, ut);

                        redone = ut;
                    }
                }
            }
        }