//
//
//
//
// $Revision: 2659 $
//
using System;
using System.Collections.Generic;
using System.Drawing;
namespace ICSharpCode.TextEditor.Undo
{
///
/// This class implements an undo stack
///
public class UndoStack
{
Stack undostack = new Stack();
Stack redostack = new Stack();
public TextEditorControlBase TextEditorControl = null;
///
///
public event EventHandler ActionUndone;
///
///
public event EventHandler ActionRedone;
///
/// Gets/Sets if changes to the document are protocolled by the undo stack.
/// Used internally to disable the undo stack temporarily while undoing an action.
///
internal bool AcceptChanges = true;
///
/// Gets if there are actions on the undo stack.
///
public bool CanUndo {
get {
return undostack.Count > 0;
}
}
///
/// Gets if there are actions on the redo stack.
///
public bool CanRedo {
get {
return redostack.Count > 0;
}
}
///
/// Gets the number of actions on the undo stack.
///
public int UndoItemCount {
get {
return undostack.Count;
}
}
///
/// Gets the number of actions on the redo stack.
///
public int RedoItemCount {
get {
return redostack.Count;
}
}
// ///
// /// You call this method to pool the last x operations from the undo stack
// /// to make 1 operation from it.
// ///
// public void CombineLast(int actionCount)
// {
// undostack.Push(new UndoQueue(undostack, actionCount));
// }
int undoGroupDepth;
int actionCountInUndoGroup;
public void StartUndoGroup()
{
if (undoGroupDepth == 0) {
actionCountInUndoGroup = 0;
}
undoGroupDepth++;
}
public void EndUndoGroup()
{
if (undoGroupDepth == 0)
return;
//throw new InvalidOperationException("There are no open undo groups");
undoGroupDepth--;
if (undoGroupDepth == 0 && actionCountInUndoGroup > 1) {
undostack.Push(new UndoQueue(undostack, actionCountInUndoGroup));
}
}
///
/// Call this method to undo the last operation on the stack
///
public void Undo()
{
while (undoGroupDepth != 0) // SSM 24.08.18 - грязный хак в попытке исправления ошибки с Ctrl-Z
{
EndUndoGroup();
}
if (undoGroupDepth != 0) {
throw new InvalidOperationException("cannot perform Undo/Redo while undo group is open");
}
if (undostack.Count > 0) {
IUndoableOperation uedit = (IUndoableOperation)undostack.Pop();
redostack.Push(uedit);
uedit.Undo();
OnActionUndone();
}
}
///
/// Call this method to redo the last undone operation
///
public void Redo()
{
if (undoGroupDepth != 0) {
throw new InvalidOperationException("cannot perform Undo/Redo while undo group is open");
}
if (redostack.Count > 0) {
IUndoableOperation uedit = (IUndoableOperation)redostack.Pop();
undostack.Push(uedit);
uedit.Redo();
OnActionRedone();
}
}
///
/// Call this method to push an UndoableOperation on the undostack, the redostack
/// will be cleared, if you use this method.
///
public void Push(IUndoableOperation operation)
{
if (operation == null) {
throw new ArgumentNullException("UndoStack.Push(UndoableOperation operation) : operation can't be null");
}
if (AcceptChanges) {
StartUndoGroup();
undostack.Push(operation);
actionCountInUndoGroup++;
if (TextEditorControl != null) {
undostack.Push(new UndoableSetCaretPosition(this, TextEditorControl.ActiveTextAreaControl.Caret.Position));
actionCountInUndoGroup++;
}
EndUndoGroup();
ClearRedoStack();
}
}
///
/// Call this method, if you want to clear the redo stack
///
public void ClearRedoStack()
{
redostack.Clear();
}
///
/// Clears both the undo and redo stack.
///
public void ClearAll()
{
undostack.Clear();
redostack.Clear();
actionCountInUndoGroup = 0;
}
///
///
protected void OnActionUndone()
{
if (ActionUndone != null) {
ActionUndone(null, null);
}
}
///
///
protected void OnActionRedone()
{
if (ActionRedone != null) {
ActionRedone(null, null);
}
}
class UndoableSetCaretPosition : IUndoableOperation
{
UndoStack stack;
TextLocation pos;
TextLocation redoPos;
public UndoableSetCaretPosition(UndoStack stack, TextLocation pos)
{
this.stack = stack;
this.pos = pos;
}
public void Undo()
{
redoPos = stack.TextEditorControl.ActiveTextAreaControl.Caret.Position;
stack.TextEditorControl.ActiveTextAreaControl.Caret.Position = pos;
}
public void Redo()
{
stack.TextEditorControl.ActiveTextAreaControl.Caret.Position = redoPos;
}
}
}
}