Exemple #1
0
        public UndoTransactionImpl(ITextUndoHistory history, ITextUndoTransaction parent, string description)
        {
            if (history == null)
            {
                throw new ArgumentNullException("history", String.Format(CultureInfo.CurrentUICulture, "Strings.ArgumentCannotBeNull", "UndoTransactionImpl", "history"));
            }

            if (String.IsNullOrEmpty(description))
            {
                throw new ArgumentNullException("description", String.Format(CultureInfo.CurrentUICulture, "Strings.ArgumentCannotBeNull", "UndoTransactionImpl", "description"));
            }

            this.history = history as UndoHistoryImpl;

            if (this.history == null)
            {
                throw new ArgumentException("Strings.InvalidHistoryInTransaction");
            }

            this.parent = parent as UndoTransactionImpl;

            if (this.parent == null && parent != null)
            {
                throw new ArgumentException("Strings.InvalidParentInTransaction");
            }

            this.description = description;

            this.state       = UndoTransactionState.Open;
            this.primitives  = new List <ITextUndoPrimitive>();
            this.mergePolicy = NullMergeUndoTransactionPolicy.Instance;
            this.IsReadOnly  = true;
        }
Exemple #2
0
        public UndoTransactionImpl(ITextUndoHistory history, ITextUndoTransaction parent, string description)
        {
            if (history == null)
            {
                throw new ArgumentNullException(nameof(history));
            }

            if (string.IsNullOrEmpty(description))
            {
                throw new ArgumentNullException(nameof(description));
            }

            this.history = history as UndoHistoryImpl;

            if (this.history == null)
            {
                throw new ArgumentException("Strings.InvalidHistoryInTransaction");
            }

            this.parent = parent as UndoTransactionImpl;

            if (this.parent == null && parent != null)
            {
                throw new ArgumentException("Strings.InvalidParentInTransaction");
            }

            this.description = description;

            this.state       = UndoTransactionState.Open;
            this.primitives  = new List <ITextUndoPrimitive>();
            this.mergePolicy = NullMergeUndoTransactionPolicy.Instance;
            this.IsReadOnly  = true;
        }
Exemple #3
0
 /// <summary>
 /// Copies all of the primitives from the given transaction, and appends them to the UndoPrimitives list.
 /// </summary>
 /// <param name="transaction">The UndoTransactionImpl to copy from.</param>
 public void CopyPrimitivesFrom(UndoTransactionImpl transaction)
 {
     foreach (ITextUndoPrimitive p in transaction.UndoPrimitives)
     {
         this.AddUndo(p);
     }
 }
        /// <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(UndoTransactionImpl transaction)
        {
            ITextUndoTransaction transactionAdded;
            TextUndoTransactionCompletionResult transactionResult;

            UndoTransactionImpl utPrevious = this.undoStack.Count > 0 ? this.undoStack.Peek() as UndoTransactionImpl : 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
            {
                this.undoStack.Push(transaction);

                transactionAdded  = transaction;
                transactionResult = TextUndoTransactionCompletionResult.TransactionAdded;
            }
            RaiseUndoTransactionCompleted(transactionAdded, transactionResult);
        }
        /// <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>
        /// <param name="isHidden">The new transaction.</param>
        /// <returns></returns>
        public ITextUndoTransaction CreateTransaction(string description)
        {
            if (String.IsNullOrEmpty(description))
            {
                throw new ArgumentNullException("description", String.Format(CultureInfo.CurrentUICulture, "Strings.ArgumentCannotBeNull", "CreateTransaction", "description"));
            }

            // 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 ((this.currentTransaction != null) && (this.currentTransaction.State != UndoTransactionState.Open))
            {
                throw new InvalidOperationException("Strings.CannotCreateTransactionWhenCurrentTransactionNotOpen");
            }

            // new transactions that are visible should clear the redo stack.
            if (this.currentTransaction == null)
            {
                foreach (UndoTransactionImpl redoTransaction in this.redoStack)
                {
                    redoTransaction.Invalidate();
                }

                this.redoStack.Clear();
            }

            UndoTransactionImpl newTransaction = new UndoTransactionImpl(this, this.currentTransaction, description);

            this.currentTransaction = newTransaction;

            return(this.currentTransaction);
        }
        private bool ProceedWithMerge(UndoTransactionImpl transaction1, UndoTransactionImpl transaction2)
        {
            UndoHistoryRegistryImpl registry = UndoHistoryRegistry;

            return(transaction1.MergePolicy != null &&
                   transaction2.MergePolicy != null &&
                   transaction1.MergePolicy.TestCompatiblePolicy(transaction2.MergePolicy) &&
                   transaction1.MergePolicy.CanMerge(transaction1, transaction2));
        }
 public UndoHistoryImpl(UndoHistoryRegistryImpl undoHistoryRegistry)
 {
     this.currentTransaction           = null;
     this.UndoHistoryRegistry          = undoHistoryRegistry;
     this.undoStack                    = new Stack <ITextUndoTransaction>();
     this.redoStack                    = new Stack <ITextUndoTransaction>();
     this.activeUndoOperationPrimitive = null;
     this.state = TextUndoHistoryState.Idle;
 }
Exemple #8
0
        public DelegatedUndoPrimitiveImpl(UndoHistoryImpl history, UndoTransactionImpl parent, UndoableOperationCurried operationCurried)
        {
            redoOperations = new Stack <UndoableOperationCurried>();
            undoOperations = new Stack <UndoableOperationCurried>();

            this.parent  = parent;
            this.history = history;
            this.state   = DelegatedUndoPrimitiveState.Inactive;

            undoOperations.Push(operationCurried);
        }
        /// <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 (this.currentTransaction != transaction)
            {
                this.currentTransaction = null;
                throw new InvalidOperationException("Strings.EndTransactionOutOfOrder");
            }

            // only add completed transactions to their parents (or the stack)
            if (this.currentTransaction.State == UndoTransactionState.Completed)
            {
                if (this.currentTransaction.Parent == null) // stack bottomed out!
                {
                    MergeOrPushToUndoStack(this.currentTransaction);
                }
            }
            this.currentTransaction = this.currentTransaction.Parent as UndoTransactionImpl;
        }
        /// <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 (this.currentTransaction != transaction)
            {
                this.currentTransaction = null;
                throw new InvalidOperationException("Strings.EndTransactionOutOfOrder");
            }

            // Note that the VS undo history actually "pops" the nested undo stack on the Complete/Cancel
            // (instead of in the Dispose). This shouldn't affect anything but we should consider adapting
            // this code to follow the model in VS undo.
            this.currentTransaction = (UndoTransactionImpl)(transaction.Parent);

            // only add completed transactions to their parents (or the stack)
            if (transaction.State == UndoTransactionState.Completed)
            {
                if (transaction.Parent == null) // stack bottomed out!
                {
                    MergeOrPushToUndoStack((UndoTransactionImpl)transaction);
                }
            }
        }
        /// <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(UndoTransactionImpl transaction)
        {
            TextUndoHistoryState originalState = this.state;

            this.state = TextUndoHistoryState.Redoing;
            using (new AutoEnclose(delegate { this.state = originalState; }))
            {
                if (this.redoStack.Contains(transaction))
                {
                    UndoTransactionImpl redone = null;
                    while (redone != transaction)
                    {
                        UndoTransactionImpl ut = this.redoStack.Pop() as UndoTransactionImpl;
                        ut.Do();
                        this.undoStack.Push(ut);

                        RaiseUndoRedoHappened(this.state, ut);

                        redone = ut;
                    }
                }
            }
        }