Browse Source

AvalonEdit: add TextEditor.IsModified property

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5760 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Daniel Grunwald 15 years ago
parent
commit
67d1aa96d3
  1. 61
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoStack.cs
  2. 75
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditor.cs

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

@ -39,6 +39,60 @@ namespace ICSharpCode.AvalonEdit.Document @@ -39,6 +39,60 @@ namespace ICSharpCode.AvalonEdit.Document
object lastGroupDescriptor;
bool allowContinue;
#region IsOriginalFile implementation
// implements feature request SD2-784 - File still considered dirty after undoing all changes
/// <summary>
/// Number of times undo must be executed until the original state is reached.
/// Negative: number of times redo must be executed until the original state is reached.
/// Special case: int.MinValue == original state is unreachable
/// </summary>
int elementsOnUndoUntilOriginalFile;
/// <summary>
/// Gets whether the document is currently in its original state (no modifications).
/// </summary>
public bool IsOriginalFile {
get { return elementsOnUndoUntilOriginalFile == 0; }
}
/// <summary>
/// Marks the current state as original. Discards any previous "original" markers.
/// </summary>
public void MarkAsOriginalFile()
{
bool oldIsOriginalFile = IsOriginalFile;
elementsOnUndoUntilOriginalFile = 0;
if (!oldIsOriginalFile)
NotifyPropertyChanged("IsOriginalFile");
}
/// <summary>
/// Discards the current "original" marker.
/// </summary>
public void DiscardOriginalFileMarker()
{
bool oldIsOriginalFile = IsOriginalFile;
elementsOnUndoUntilOriginalFile = int.MinValue;
if (oldIsOriginalFile)
NotifyPropertyChanged("IsOriginalFile");
}
void FileModified(int newElementsOnUndoStack)
{
if (newElementsOnUndoStack == 0 || elementsOnUndoUntilOriginalFile == int.MinValue)
return;
bool oldIsOriginalFile = IsOriginalFile;
elementsOnUndoUntilOriginalFile += newElementsOnUndoStack;
if (elementsOnUndoUntilOriginalFile > undostack.Count)
elementsOnUndoUntilOriginalFile = int.MinValue;
if (oldIsOriginalFile != IsOriginalFile)
NotifyPropertyChanged("IsOriginalFile");
}
#endregion
/// <summary>
/// Gets if the undo stack currently accepts changes.
/// Is false while an undo action is running.
@ -166,9 +220,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -166,9 +220,11 @@ namespace ICSharpCode.AvalonEdit.Document
} else if (actionCountInUndoGroup > 1) {
// combine all actions within the group into a single grouped action
undostack.PushBack(new UndoOperationGroup(undostack, actionCountInUndoGroup));
actionCountInUndoGroup = 1; // actions were combined
}
EnforceSizeLimit();
allowContinue = true;
FileModified(actionCountInUndoGroup);
}
}
@ -204,6 +260,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -204,6 +260,7 @@ namespace ICSharpCode.AvalonEdit.Document
} finally {
state = StateListen;
}
FileModified(-1);
if (undostack.Count == 0)
NotifyPropertyChanged("CanUndo");
if (redostack.Count == 1)
@ -236,6 +293,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -236,6 +293,7 @@ namespace ICSharpCode.AvalonEdit.Document
} finally {
state = StateListen;
}
FileModified(1);
if (redostack.Count == 0)
NotifyPropertyChanged("CanRedo");
if (undostack.Count == 1)
@ -304,6 +362,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -304,6 +362,9 @@ namespace ICSharpCode.AvalonEdit.Document
if (redostack.Count != 0) {
redostack.Clear();
NotifyPropertyChanged("CanRedo");
// if the "orginal file" marker is on the redo stack: remove it
if (elementsOnUndoUntilOriginalFile < 0)
elementsOnUndoUntilOriginalFile = int.MinValue;
}
}

75
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditor.cs

@ -121,10 +121,12 @@ namespace ICSharpCode.AvalonEdit @@ -121,10 +121,12 @@ namespace ICSharpCode.AvalonEdit
{
if (oldValue != null) {
TextDocumentWeakEventManager.TextChanged.RemoveListener(oldValue, this);
PropertyChangedEventManager.RemoveListener(oldValue.UndoStack, this, "IsOriginalFile");
}
textArea.Document = newValue;
if (newValue != null) {
TextDocumentWeakEventManager.TextChanged.AddListener(newValue, this);
PropertyChangedEventManager.AddListener(newValue.UndoStack, this, "IsOriginalFile");
}
OnDocumentChanged(EventArgs.Empty);
OnTextChanged(EventArgs.Empty);
@ -187,6 +189,8 @@ namespace ICSharpCode.AvalonEdit @@ -187,6 +189,8 @@ namespace ICSharpCode.AvalonEdit
} else if (managerType == typeof(TextDocumentWeakEventManager.TextChanged)) {
OnTextChanged(e);
return true;
} else if (managerType == typeof(PropertyChangedEventManager)) {
return HandleIsOriginalChanged((PropertyChangedEventArgs)e);
}
return false;
}
@ -208,10 +212,8 @@ namespace ICSharpCode.AvalonEdit @@ -208,10 +212,8 @@ namespace ICSharpCode.AvalonEdit
return document != null ? document.Text : string.Empty;
}
set {
if (value == null)
value = string.Empty;
TextDocument document = GetDocument();
document.Text = value;
document.Text = value ?? string.Empty;
// after replacing the full text, the caret is positioned at the end of the document
// - reset it to the beginning.
this.CaretOffset = 0;
@ -391,6 +393,53 @@ namespace ICSharpCode.AvalonEdit @@ -391,6 +393,53 @@ namespace ICSharpCode.AvalonEdit
}
#endregion
#region IsModified
/// <summary>
/// Dependency property for <see cref="IsModified"/>
/// </summary>
public static readonly DependencyProperty IsModifiedProperty =
DependencyProperty.Register("IsModified", typeof(bool), typeof(TextEditor),
new FrameworkPropertyMetadata(Boxes.False, OnIsModifiedChanged));
/// <summary>
/// Gets/Sets the 'modified' flag.
/// </summary>
public bool IsModified {
get { return (bool)GetValue(IsModifiedProperty); }
set { SetValue(IsModifiedProperty, value); }
}
static void OnIsModifiedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextEditor editor = d as TextEditor;
if (editor != null) {
TextDocument document = editor.Document;
if (document != null) {
UndoStack undoStack = document.UndoStack;
if ((bool)e.NewValue) {
if (undoStack.IsOriginalFile)
undoStack.DiscardOriginalFileMarker();
} else {
undoStack.MarkAsOriginalFile();
}
}
}
}
bool HandleIsOriginalChanged(PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsOriginalFile") {
TextDocument document = this.Document;
if (document != null) {
this.IsModified = !document.UndoStack.IsOriginalFile;
}
return true;
} else {
return false;
}
}
#endregion
#region ShowLineNumbers
/// <summary>
/// IsReadOnly dependency property.
@ -825,12 +874,16 @@ namespace ICSharpCode.AvalonEdit @@ -825,12 +874,16 @@ namespace ICSharpCode.AvalonEdit
/// <summary>
/// Loads the text from the stream, auto-detecting the encoding.
/// </summary>
/// <remarks>
/// This method sets <see cref="IsModified"/> to false.
/// </remarks>
public void Load(Stream stream)
{
using (StreamReader reader = FileReader.OpenStream(stream, Encoding ?? Encoding.UTF8)) {
Text = reader.ReadToEnd();
Encoding = reader.CurrentEncoding; // assign encoding after ReadToEnd() so that the StreamReader can autodetect the encoding
using (StreamReader reader = FileReader.OpenStream(stream, this.Encoding ?? Encoding.UTF8)) {
this.Text = reader.ReadToEnd();
this.Encoding = reader.CurrentEncoding; // assign encoding after ReadToEnd() so that the StreamReader can autodetect the encoding
}
this.IsModified = false;
}
/// <summary>
@ -854,18 +907,22 @@ namespace ICSharpCode.AvalonEdit @@ -854,18 +907,22 @@ namespace ICSharpCode.AvalonEdit
/// <summary>
/// Saves the text to the stream.
/// </summary>
/// <remarks>
/// This method sets <see cref="IsModified"/> to false.
/// </remarks>
public void Save(Stream stream)
{
if (stream == null)
throw new ArgumentNullException("stream");
StreamWriter writer = new StreamWriter(stream, Encoding ?? Encoding.UTF8);
writer.Write(Text);
StreamWriter writer = new StreamWriter(stream, this.Encoding ?? Encoding.UTF8);
writer.Write(this.Text);
writer.Flush();
// do not close the stream
this.IsModified = false;
}
/// <summary>
/// Loads the text from the stream, auto-detecting the encoding.
/// Saves the text to the file.
/// </summary>
public void Save(string fileName)
{

Loading…
Cancel
Save