/// <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) { if (string.IsNullOrEmpty(description)) { throw new ArgumentException("description", string.Format(CultureInfo.CurrentUICulture, "Strings.ArgumentCannotBeNull {0} {1}", "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 ((_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 = (UndoTransactionImpl)textUndoTransaction; redoTransaction.Invalidate(); } _redoStack.Clear(); } UndoTransactionImpl newTransaction = new UndoTransactionImpl(this, _currentTransaction, description); _currentTransaction = newTransaction; return(_currentTransaction); }
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)); } _history = history as UndoHistoryImpl; if (_history == null) { throw new ArgumentException("Invalid history in registry"); } _parent = parent as UndoTransactionImpl; if (_parent == null && parent != null) { throw new ArgumentException("Invalid parent in transaction"); } Description = description; _state = UndoTransactionState.Open; _primitives = new List<ITextUndoPrimitive>(); _mergePolicy = NullMergeUndoTransactionPolicy.Instance; IsReadOnly = true; }
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)); } _history = history as UndoHistoryImpl; if (_history == null) { throw new ArgumentException("Invalid history in registry"); } _parent = parent as UndoTransactionImpl; if (_parent == null && parent != null) { throw new ArgumentException("Invalid parent in transaction"); } Description = description; _state = UndoTransactionState.Open; _primitives = new List <ITextUndoPrimitive>(); _mergePolicy = NullMergeUndoTransactionPolicy.Instance; IsReadOnly = true; }
/// <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 (var p in transaction.UndoPrimitives) { 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 = _undoStack.Count > 0 ? _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 { _undoStack.Push(transaction); transactionAdded = transaction; transactionResult = TextUndoTransactionCompletionResult.TransactionAdded; } RaiseUndoTransactionCompleted(transactionAdded, transactionResult); }
public UndoHistoryImpl(UndoHistoryRegistryImpl undoHistoryRegistry) { _currentTransaction = null; UndoHistoryRegistry = undoHistoryRegistry; _undoStack = new Stack<ITextUndoTransaction>(); _redoStack = new Stack<ITextUndoTransaction>(); _activeUndoOperationPrimitive = null; _state = TextUndoHistoryState.Idle; }
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) { _currentTransaction = null; UndoHistoryRegistry = undoHistoryRegistry; _undoStack = new Stack <ITextUndoTransaction>(); _redoStack = new Stack <ITextUndoTransaction>(); _activeUndoOperationPrimitive = null; _state = TextUndoHistoryState.Idle; }
public DelegatedUndoPrimitiveImpl(UndoHistoryImpl history, UndoTransactionImpl parent, UndoableOperationCurried operationCurried) { RedoOperations = new Stack<UndoableOperationCurried>(); _undoOperations = new Stack<UndoableOperationCurried>(); _parent = parent; _history = history; _state = DelegatedUndoPrimitiveState.Inactive; _undoOperations.Push(operationCurried); }
public DelegatedUndoPrimitiveImpl(UndoHistoryImpl history, UndoTransactionImpl parent, UndoableOperationCurried operationCurried) { RedoOperations = new Stack <UndoableOperationCurried>(); _undoOperations = new Stack <UndoableOperationCurried>(); _parent = parent; _history = history; _state = DelegatedUndoPrimitiveState.Inactive; _undoOperations.Push(operationCurried); }
public UndoTransactionImpl(ITextUndoHistory history, ITextUndoTransaction parent, string description) { Check.ArgumentNull(nameof(history), history); Check.ArgumentStringNullOrEmpty(nameof(description), description); _history = history as UndoHistoryImpl; Check.ArgumentNull(nameof(history), _history); _parent = parent as UndoTransactionImpl; Check.Argument(nameof(parent), () => _parent != null || parent == null); Description = description; _state = UndoTransactionState.Open; _primitives = new List <ITextUndoPrimitive>(); _mergePolicy = NullMergeUndoTransactionPolicy.Instance; IsReadOnly = true; }
/// <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 UndoTransactionImpl; }
/// <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 = _state; _state = TextUndoHistoryState.Redoing; using (new AutoEnclose(delegate { this._state = originalState; })) { if (_redoStack.Contains(transaction)) { UndoTransactionImpl redone = null; while (redone != transaction) { UndoTransactionImpl ut = _redoStack.Pop() as UndoTransactionImpl; ut.Do(); _undoStack.Push(ut); RaiseUndoRedoHappened(_state, ut); redone = ut; } } } }
/// <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) { if (string.IsNullOrEmpty(description)) { throw new ArgumentException("description", string.Format(CultureInfo.CurrentUICulture, "Strings.ArgumentCannotBeNull {0} {1}", "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 ((_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 = (UndoTransactionImpl) textUndoTransaction; redoTransaction.Invalidate(); } _redoStack.Clear(); } UndoTransactionImpl newTransaction = new UndoTransactionImpl(this, _currentTransaction, description); _currentTransaction = newTransaction; return _currentTransaction; }
/// <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 UndoTransactionImpl; }
/// <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 = _undoStack.Count > 0 ? _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 { _undoStack.Push(transaction); transactionAdded = transaction; transactionResult = TextUndoTransactionCompletionResult.TransactionAdded; } RaiseUndoTransactionCompleted(transactionAdded, transactionResult); }
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); }
/// <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) { AddUndo(p); } }
/// <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 = _state; _state = TextUndoHistoryState.Redoing; using (new AutoEnclose(delegate { this._state = originalState; })) { if (_redoStack.Contains(transaction)) { UndoTransactionImpl redone = null; while (redone != transaction) { UndoTransactionImpl ut = _redoStack.Pop() as UndoTransactionImpl; ut.Do(); _undoStack.Push(ut); RaiseUndoRedoHappened(_state, ut); redone = ut; } } } }