Browse Source

Implemented SizeLimit for UndoStack.

This allows disabling the undo stack as requested in forum-10585.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5383 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Daniel Grunwald 16 years ago
parent
commit
3839873b7e
  1. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoOperationGroup.cs
  2. 55
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoStack.cs
  3. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs
  4. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs
  5. 1
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
  6. 1
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Properties/CodeAnalysisDictionary.xml
  7. 177
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/Deque.cs
  8. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/TextFormatterFactory.cs

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoOperationGroup.cs

@ -6,8 +6,8 @@ @@ -6,8 +6,8 @@
// </file>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Document
{
@ -19,7 +19,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -19,7 +19,7 @@ namespace ICSharpCode.AvalonEdit.Document
{
IUndoableOperation[] undolist;
public UndoOperationGroup(Stack<IUndoableOperation> stack, int numops)
public UndoOperationGroup(Deque<IUndoableOperation> stack, int numops)
{
if (stack == null) {
throw new ArgumentNullException("stack");
@ -31,7 +31,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -31,7 +31,7 @@ namespace ICSharpCode.AvalonEdit.Document
}
undolist = new IUndoableOperation[numops];
for (int i = 0; i < numops; ++i) {
undolist[i] = stack.Pop();
undolist[i] = stack.PopBack();
}
}

55
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoStack.cs

@ -6,8 +6,10 @@ @@ -6,8 +6,10 @@
// </file>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Document
{
@ -17,9 +19,10 @@ namespace ICSharpCode.AvalonEdit.Document @@ -17,9 +19,10 @@ namespace ICSharpCode.AvalonEdit.Document
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
public sealed class UndoStack : INotifyPropertyChanged
{
Stack<IUndoableOperation> undostack = new Stack<IUndoableOperation>();
Stack<IUndoableOperation> redostack = new Stack<IUndoableOperation>();
Deque<IUndoableOperation> undostack = new Deque<IUndoableOperation>();
Deque<IUndoableOperation> redostack = new Deque<IUndoableOperation>();
int sizeLimit = 1000;
bool acceptChanges = true;
/// <summary>
@ -46,6 +49,35 @@ namespace ICSharpCode.AvalonEdit.Document @@ -46,6 +49,35 @@ namespace ICSharpCode.AvalonEdit.Document
get { return redostack.Count > 0; }
}
/// <summary>
/// Gets/Sets the limit on the number of items on the undo stack.
/// The default value is 1000.
/// </summary>
/// <remarks>The size limit is enforced only on the number of stored top-level undo groups.
/// Elements within undo groups do not count towards the size limit.</remarks>
public int SizeLimit {
get { return sizeLimit; }
set {
if (value < 0)
ThrowUtil.CheckNotNegative(value, "value");
if (sizeLimit != value) {
sizeLimit = value;
NotifyPropertyChanged("SizeLimit");
if (undoGroupDepth == 0)
EnforceSizeLimit();
}
}
}
void EnforceSizeLimit()
{
Debug.Assert(undoGroupDepth == 0);
while (undostack.Count > sizeLimit)
undostack.PopFront();
while (redostack.Count > sizeLimit)
redostack.PopFront();
}
int undoGroupDepth;
int actionCountInUndoGroup;
int optionalActionCount;
@ -121,11 +153,12 @@ namespace ICSharpCode.AvalonEdit.Document @@ -121,11 +153,12 @@ namespace ICSharpCode.AvalonEdit.Document
if (actionCountInUndoGroup == optionalActionCount) {
// only optional actions: don't store them
for (int i = 0; i < optionalActionCount; i++) {
undostack.Pop();
undostack.PopBack();
}
} else if (actionCountInUndoGroup > 1) {
undostack.Push(new UndoOperationGroup(undostack, actionCountInUndoGroup));
undostack.PushBack(new UndoOperationGroup(undostack, actionCountInUndoGroup));
}
EnforceSizeLimit();
}
}
@ -149,8 +182,8 @@ namespace ICSharpCode.AvalonEdit.Document @@ -149,8 +182,8 @@ namespace ICSharpCode.AvalonEdit.Document
if (undostack.Count > 0) {
lastGroupDescriptor = null;
acceptChanges = false;
IUndoableOperation uedit = undostack.Pop();
redostack.Push(uedit);
IUndoableOperation uedit = undostack.PopBack();
redostack.PushBack(uedit);
uedit.Undo();
acceptChanges = true;
if (undostack.Count == 0)
@ -169,8 +202,8 @@ namespace ICSharpCode.AvalonEdit.Document @@ -169,8 +202,8 @@ namespace ICSharpCode.AvalonEdit.Document
if (redostack.Count > 0) {
lastGroupDescriptor = null;
acceptChanges = false;
IUndoableOperation uedit = redostack.Pop();
undostack.Push(uedit);
IUndoableOperation uedit = redostack.PopBack();
undostack.PushBack(uedit);
uedit.Redo();
acceptChanges = true;
if (redostack.Count == 0)
@ -209,11 +242,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -209,11 +242,11 @@ namespace ICSharpCode.AvalonEdit.Document
throw new ArgumentNullException("operation");
}
if (acceptChanges) {
if (acceptChanges && sizeLimit > 0) {
bool wasEmpty = undostack.Count == 0;
StartUndoGroup();
undostack.Push(operation);
undostack.PushBack(operation);
actionCountInUndoGroup++;
if (isOptional)
optionalActionCount++;

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs

@ -65,7 +65,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -65,7 +65,7 @@ namespace ICSharpCode.AvalonEdit.Editing
/// <summary>
/// Creates a new TextAreaInputHandler.
/// </summary>
public TextAreaStackedInputHandler(TextArea textArea)
protected TextAreaStackedInputHandler(TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs

@ -88,6 +88,8 @@ namespace ICSharpCode.AvalonEdit.Highlighting @@ -88,6 +88,8 @@ namespace ICSharpCode.AvalonEdit.Highlighting
/// </summary>
public void SetHighlighting(int offset, int length, HighlightingColor color)
{
if (color == null)
throw new ArgumentNullException("color");
int startIndex = GetIndexForOffset(offset);
int endIndex = GetIndexForOffset(offset + length);
for (int i = startIndex; i < endIndex; i++) {

1
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

@ -319,6 +319,7 @@ @@ -319,6 +319,7 @@
<Compile Include="Utils\Constants.cs" />
<Compile Include="Utils\DelayedEvents.cs" />
<Compile Include="Utils\CallbackOnDispose.cs" />
<Compile Include="Utils\Deque.cs" />
<Compile Include="Utils\Empty.cs" />
<Compile Include="Utils\ExtensionMethods.cs" />
<Compile Include="Utils\FileReader.cs" />

1
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Properties/CodeAnalysisDictionary.xml

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
<Word>Foldings</Word>
<Word>Xshd</Word>
<Word>Utils</Word>
<Word>Deque</Word>
<Word>Colorizer</Word>
<Word>Renderer</Word>
<Word>Renderers</Word>

177
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/Deque.cs

@ -0,0 +1,177 @@ @@ -0,0 +1,177 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ICSharpCode.AvalonEdit.Utils
{
/// <summary>
/// Double-ended queue.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
public class Deque<T> : ICollection<T>
{
T[] arr = Empty<T>.Array;
int size, head, tail;
/// <inheritdoc/>
public int Count {
get { return size; }
}
/// <inheritdoc/>
public void Clear()
{
arr = Empty<T>.Array;
size = 0;
head = 0;
tail = 0;
}
/// <summary>
/// Gets/Sets an element inside the deque.
/// </summary>
public T this[int index] {
get {
ThrowUtil.CheckInRangeInclusive(index, "index", 0, size - 1);
return arr[(head + index) % arr.Length];
}
set {
ThrowUtil.CheckInRangeInclusive(index, "index", 0, size - 1);
arr[(head + index) % arr.Length] = value;
}
}
/// <summary>
/// Adds an element to the end of the deque.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "PushBack")]
public void PushBack(T item)
{
if (size == arr.Length)
SetCapacity(Math.Max(4, arr.Length * 2));
arr[tail++] = item;
if (tail == arr.Length) tail = 0;
size++;
}
/// <summary>
/// Pops an element from the end of the deque.
/// </summary>
public T PopBack()
{
if (size == 0)
throw new InvalidOperationException();
if (tail == 0)
tail = arr.Length - 1;
else
tail--;
T val = arr[tail];
arr[tail] = default(T); // allow GC to collect the element
size--;
return val;
}
/// <summary>
/// Adds an element to the front of the deque.
/// </summary>
public void PushFront(T item)
{
if (size == arr.Length)
SetCapacity(Math.Max(4, arr.Length * 2));
if (head == 0)
head = arr.Length - 1;
else
head--;
arr[head] = item;
size++;
}
/// <summary>
/// Pops an element from the end of the deque.
/// </summary>
public T PopFront()
{
if (size == 0)
throw new InvalidOperationException();
T val = arr[head];
arr[head] = default(T); // allow GC to collect the element
head++;
if (head == arr.Length) head = 0;
size--;
return val;
}
void SetCapacity(int capacity)
{
T[] newArr = new T[capacity];
CopyTo(newArr, 0);
head = 0;
tail = (size == capacity) ? 0 : size;
arr = newArr;
}
/// <inheritdoc/>
public IEnumerator<T> GetEnumerator()
{
if (head < tail) {
for (int i = head; i < tail; i++)
yield return arr[i];
} else {
for (int i = head; i < arr.Length; i++)
yield return arr[i];
for (int i = 0; i < tail; i++)
yield return arr[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
bool ICollection<T>.IsReadOnly {
get { return false; }
}
void ICollection<T>.Add(T item)
{
PushBack(item);
}
/// <inheritdoc/>
public bool Contains(T item)
{
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
foreach (T element in this)
if (comparer.Equals(item, element))
return true;
return false;
}
/// <inheritdoc/>
public void CopyTo(T[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException("array");
if (head < tail) {
Array.Copy(arr, head, array, arrayIndex, tail - head);
} else {
int num1 = arr.Length - head;
Array.Copy(arr, head, array, arrayIndex, num1);
Array.Copy(arr, 0, array, arrayIndex + num1, tail);
}
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
}
}

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/TextFormatterFactory.cs

@ -45,7 +45,8 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -45,7 +45,8 @@ namespace ICSharpCode.AvalonEdit.Utils
"Create",
BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
null, null,
new object[] { formattingMode });
new object[] { formattingMode },
CultureInfo.InvariantCulture);
} else {
return TextFormatter.Create();
}

Loading…
Cancel
Save