Browse Source

implemented DefaultChangeWatcher

pull/15/head
Siegfried Pammer 16 years ago
parent
commit
b13d1002df
  1. 244
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs

244
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs

@ -2,15 +2,15 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Generic; using System.ComponentModel;
using System.Linq; using System.Diagnostics;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.SharpDevelop; using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor;
namespace ICSharpCode.AvalonEdit.AddIn namespace ICSharpCode.AvalonEdit.AddIn
@ -22,15 +22,10 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
IChangeWatcher changeWatcher; IChangeWatcher changeWatcher;
public IChangeWatcher ChangeWatcher { public ChangeMarkerMargin()
get { return changeWatcher; } {
set { changeWatcher = new DefaultChangeWatcher();
if (changeWatcher != null) changeWatcher.ChangeOccurred += new EventHandler(ChangeOccurred);
changeWatcher.ChangeOccured -= ChangeOccured;
changeWatcher = value;
if (changeWatcher != null)
changeWatcher.ChangeOccured += ChangeOccured;
}
} }
protected override void OnRender(DrawingContext drawingContext) protected override void OnRender(DrawingContext drawingContext)
@ -40,6 +35,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
if (textView != null && textView.VisualLinesValid) { if (textView != null && textView.VisualLinesValid) {
ITextEditor editor = textView.Services.GetService(typeof(ITextEditor)) as ITextEditor; ITextEditor editor = textView.Services.GetService(typeof(ITextEditor)) as ITextEditor;
changeWatcher.Initialize(editor.Document);
foreach (VisualLine line in textView.VisualLines) { foreach (VisualLine line in textView.VisualLines) {
Rect rect = new Rect(0, line.VisualTop - textView.ScrollOffset.Y, renderSize.Width, line.Height); Rect rect = new Rect(0, line.VisualTop - textView.ScrollOffset.Y, renderSize.Width, line.Height);
@ -50,12 +46,8 @@ namespace ICSharpCode.AvalonEdit.AddIn
case ChangeType.None: case ChangeType.None:
break; break;
case ChangeType.Added: case ChangeType.Added:
case ChangeType.Saved:
drawingContext.DrawRectangle(Brushes.LightGreen, null, rect); drawingContext.DrawRectangle(Brushes.LightGreen, null, rect);
break; break;
case ChangeType.Deleted:
// TODO : implement
break;
case ChangeType.Modified: case ChangeType.Modified:
drawingContext.DrawRectangle(Brushes.Blue, null, rect); drawingContext.DrawRectangle(Brushes.Blue, null, rect);
break; break;
@ -71,9 +63,6 @@ namespace ICSharpCode.AvalonEdit.AddIn
protected override void OnTextViewChanged(TextView oldTextView, TextView newTextView) protected override void OnTextViewChanged(TextView oldTextView, TextView newTextView)
{ {
if (ChangeWatcher == null)
ChangeWatcher = new LocalChangeWatcher();
if (oldTextView != null) { if (oldTextView != null) {
oldTextView.VisualLinesChanged -= VisualLinesChanged; oldTextView.VisualLinesChanged -= VisualLinesChanged;
oldTextView.ScrollOffsetChanged -= ScrollOffsetChanged; oldTextView.ScrollOffsetChanged -= ScrollOffsetChanged;
@ -82,19 +71,12 @@ namespace ICSharpCode.AvalonEdit.AddIn
if (newTextView != null) { if (newTextView != null) {
newTextView.VisualLinesChanged += VisualLinesChanged; newTextView.VisualLinesChanged += VisualLinesChanged;
newTextView.ScrollOffsetChanged += ScrollOffsetChanged; newTextView.ScrollOffsetChanged += ScrollOffsetChanged;
ITextEditor editor = newTextView.Services.GetService(typeof(ITextEditor)) as ITextEditor;
changeWatcher.UpdateTextEditor(editor);
} }
} }
protected override void OnDocumentChanged(TextDocument oldDocument, TextDocument newDocument) void ChangeOccurred(object sender, EventArgs e)
{ {
if (ChangeWatcher == null) InvalidateVisual();
ChangeWatcher = new LocalChangeWatcher();
ITextEditor editor = TextView.Services.GetService(typeof(ITextEditor)) as ITextEditor;
changeWatcher.UpdateTextEditor(editor);
} }
void VisualLinesChanged(object sender, EventArgs e) void VisualLinesChanged(object sender, EventArgs e)
@ -107,11 +89,6 @@ namespace ICSharpCode.AvalonEdit.AddIn
InvalidateVisual(); InvalidateVisual();
} }
void ChangeOccured(object sender, EventArgs e)
{
InvalidateVisual();
}
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
return new Size(5, 0); return new Size(5, 0);
@ -124,7 +101,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
if (!disposed) { if (!disposed) {
OnTextViewChanged(TextView, null); OnTextViewChanged(TextView, null);
changeWatcher.Dispose(); changeWatcher.Dispose();
ChangeWatcher = null; changeWatcher = null;
disposed = true; disposed = true;
} }
} }
@ -132,95 +109,157 @@ namespace ICSharpCode.AvalonEdit.AddIn
public interface IChangeWatcher : IDisposable public interface IChangeWatcher : IDisposable
{ {
event EventHandler ChangeOccured; event EventHandler ChangeOccurred;
ChangeType GetChange(IDocumentLine line); ChangeType GetChange(IDocumentLine line);
void UpdateTextEditor(ITextEditor editor); void Initialize(IDocument document);
} }
public enum ChangeType : int public enum ChangeType
{ {
None = 0x0000, None,
Added = 0x0001, Added,
Deleted = 0x0002, Modified,
Modified = 0x0004, Unsaved
/// <summary> }
/// Only to be used by LocalChangeWatcher. States if a change is unsaved or not.
/// </summary> public class DefaultChangeWatcher : IChangeWatcher, ILineTracker
Saved = 0x0008, {
/// <summary> struct LineChangeInfo : IEquatable<LineChangeInfo>
/// Only to be used by LocalChangeWatcher. States if a change is unsaved or not. {
/// </summary> ChangeType change;
Unsaved = 0x0016
public ChangeType Change {
get { return change; }
set { change = value; }
}
string deletedLinesAfterThisLine;
public string DeletedLinesAfterThisLine {
get { return deletedLinesAfterThisLine; }
set { deletedLinesAfterThisLine = value; }
}
public LineChangeInfo(ChangeType change, string deletedLinesAfterThisLine)
{
this.change = change;
this.deletedLinesAfterThisLine = deletedLinesAfterThisLine;
}
#region Equals and GetHashCode implementation
public override bool Equals(object obj)
{
return (obj is DefaultChangeWatcher.LineChangeInfo) && Equals((DefaultChangeWatcher.LineChangeInfo)obj);
}
public bool Equals(DefaultChangeWatcher.LineChangeInfo other)
{
return this.change == other.change && this.deletedLinesAfterThisLine == other.deletedLinesAfterThisLine;
}
public override int GetHashCode()
{
int hashCode = 0;
unchecked {
hashCode += 1000000007 * change.GetHashCode();
if (deletedLinesAfterThisLine != null)
hashCode += 1000000009 * deletedLinesAfterThisLine.GetHashCode();
}
return hashCode;
}
public static bool operator ==(DefaultChangeWatcher.LineChangeInfo lhs, DefaultChangeWatcher.LineChangeInfo rhs)
{
return lhs.Equals(rhs);
} }
public class LocalChangeWatcher : IChangeWatcher, ILineTracker public static bool operator !=(DefaultChangeWatcher.LineChangeInfo lhs, DefaultChangeWatcher.LineChangeInfo rhs)
{ {
return !(lhs == rhs);
}
#endregion
}
WeakLineTracker lineTracker; WeakLineTracker lineTracker;
List<DocumentLine> changedLines; CompressingTreeList<LineChangeInfo> changeList;
List<DocumentLine> lastSavedChangedLines; TextDocument document;
bool changed;
OpenedFile openedFile;
TextView textView;
ITextEditor editor;
public event EventHandler ChangeOccured; public event EventHandler ChangeOccurred;
protected void OnChangeOccured(EventArgs e) protected void OnChangeOccurred(EventArgs e)
{ {
if (ChangeOccured != null) { if (ChangeOccurred != null) {
ChangeOccured(this, e); ChangeOccurred(this, e);
} }
} }
public ChangeType GetChange(IDocumentLine line) public ChangeType GetChange(IDocumentLine line)
{ {
if (openedFile == null && editor.FileName != null) { return changeList[line.LineNumber].Change;
openedFile = FileService.GetOpenedFile(editor.FileName);
openedFile.IsDirtyChanged += IsDirtyChanged;
} }
DocumentLine documentLine = textView.Document.GetLineByNumber(line.LineNumber); public void Initialize(IDocument document)
{
if (this.document != null)
return;
this.document = ((TextView)document.GetService(typeof(TextView))).Document;
this.changeList = new CompressingTreeList<LineChangeInfo>((x, y) => x.Equals(y));
if (lastSavedChangedLines.Contains(documentLine)) SetupInitialFileState();
return ChangeType.Saved;
if (changedLines.Contains(documentLine))
return ChangeType.Unsaved;
return ChangeType.None; lineTracker = WeakLineTracker.Register(this.document, this);
this.document.UndoStack.PropertyChanged += UndoStackPropertyChanged;
} }
void IsDirtyChanged(object sender, EventArgs e) void SetupInitialFileState()
{ {
if (changed && !openedFile.IsDirty) { changeList.Clear();
lastSavedChangedLines = lastSavedChangedLines.Concat(changedLines).Distinct().ToList(); changeList.InsertRange(0, this.document.LineCount + 1, new LineChangeInfo(ChangeType.None, ""));
changedLines.Clear(); OnChangeOccurred(EventArgs.Empty);
changed = false;
OnChangeOccured(EventArgs.Empty);
} }
void UndoStackPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (document.UndoStack.IsOriginalFile)
SetupInitialFileState();
} }
void ILineTracker.BeforeRemoveLine(DocumentLine line) void ILineTracker.BeforeRemoveLine(DocumentLine line)
{ {
changedLines.Remove(line); int index = line.LineNumber;
lastSavedChangedLines.Remove(line); LineChangeInfo info = changeList[index];
changed = true; LineChangeInfo lineBefore = changeList[index - 1];
lineBefore.DeletedLinesAfterThisLine
+= (document.GetText(line.Offset, line.Length)
+ Environment.NewLine + info.DeletedLinesAfterThisLine);
Debug.Assert(lineBefore.DeletedLinesAfterThisLine.EndsWith(Environment.NewLine));
changeList[index - 1] = lineBefore;
changeList.RemoveAt(index);
} }
void ILineTracker.SetLineLength(DocumentLine line, int newTotalLength) void ILineTracker.SetLineLength(DocumentLine line, int newTotalLength)
{ {
if (!changedLines.Contains(line)) int index = line.LineNumber;
changedLines.Add(line); var info = changeList[index];
lastSavedChangedLines.Remove(line); info.Change = ChangeType.Unsaved;
changed = true; changeList[index] = info;
} }
void ILineTracker.LineInserted(DocumentLine insertionPos, DocumentLine newLine) void ILineTracker.LineInserted(DocumentLine insertionPos, DocumentLine newLine)
{ {
if (!changedLines.Contains(insertionPos)) int index = insertionPos.LineNumber;
changedLines.Add(insertionPos); var firstLine = changeList[index];
lastSavedChangedLines.Remove(insertionPos); var newLineInfo = new LineChangeInfo(ChangeType.Unsaved, firstLine.DeletedLinesAfterThisLine);
changedLines.Add(newLine);
changed = true; firstLine.Change = ChangeType.Unsaved;
firstLine.DeletedLinesAfterThisLine = "";
changeList.Insert(index + 1, newLineInfo);
changeList[index] = firstLine;
} }
void ILineTracker.RebuildDocument() void ILineTracker.RebuildDocument()
@ -233,36 +272,9 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
if (!disposed) { if (!disposed) {
lineTracker.Deregister(); lineTracker.Deregister();
openedFile.IsDirtyChanged -= IsDirtyChanged; this.document.UndoStack.PropertyChanged -= UndoStackPropertyChanged;
FileService.FileCreated -= FileServiceFileCreated;
disposed = true; disposed = true;
} }
} }
public void UpdateTextEditor(ITextEditor editor)
{
if (lineTracker != null)
lineTracker.Deregister();
if (openedFile != null)
openedFile.IsDirtyChanged -= IsDirtyChanged;
if (editor == null)
throw new ArgumentNullException("editor");
this.editor = editor;
this.textView = editor.GetService(typeof(TextView)) as TextView;
FileService.FileCreated += FileServiceFileCreated;
lineTracker = WeakLineTracker.Register(textView.Document, this);
changed = false;
changedLines = new List<DocumentLine>();
lastSavedChangedLines = new List<DocumentLine>();
}
void FileServiceFileCreated(object sender, FileEventArgs e)
{
}
} }
} }

Loading…
Cancel
Save