From b13d1002df1b97d239c13308b57b8a89d3598de5 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 18 Sep 2010 18:14:57 +0200 Subject: [PATCH] implemented DefaultChangeWatcher --- .../Src/ChangeMarkerMargin.cs | 252 +++++++++--------- 1 file changed, 132 insertions(+), 120 deletions(-) diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs index 7115b30330..543c4375c5 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs +++ b/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) using System; -using System.Collections.Generic; -using System.Linq; +using System.ComponentModel; +using System.Diagnostics; using System.Windows; using System.Windows.Media; + using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Editing; -using ICSharpCode.AvalonEdit.Folding; using ICSharpCode.AvalonEdit.Rendering; -using ICSharpCode.SharpDevelop; +using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.SharpDevelop.Editor; namespace ICSharpCode.AvalonEdit.AddIn @@ -22,15 +22,10 @@ namespace ICSharpCode.AvalonEdit.AddIn { IChangeWatcher changeWatcher; - public IChangeWatcher ChangeWatcher { - get { return changeWatcher; } - set { - if (changeWatcher != null) - changeWatcher.ChangeOccured -= ChangeOccured; - changeWatcher = value; - if (changeWatcher != null) - changeWatcher.ChangeOccured += ChangeOccured; - } + public ChangeMarkerMargin() + { + changeWatcher = new DefaultChangeWatcher(); + changeWatcher.ChangeOccurred += new EventHandler(ChangeOccurred); } protected override void OnRender(DrawingContext drawingContext) @@ -40,6 +35,7 @@ namespace ICSharpCode.AvalonEdit.AddIn if (textView != null && textView.VisualLinesValid) { ITextEditor editor = textView.Services.GetService(typeof(ITextEditor)) as ITextEditor; + changeWatcher.Initialize(editor.Document); foreach (VisualLine line in textView.VisualLines) { 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: break; case ChangeType.Added: - case ChangeType.Saved: drawingContext.DrawRectangle(Brushes.LightGreen, null, rect); break; - case ChangeType.Deleted: - // TODO : implement - break; case ChangeType.Modified: drawingContext.DrawRectangle(Brushes.Blue, null, rect); break; @@ -71,9 +63,6 @@ namespace ICSharpCode.AvalonEdit.AddIn protected override void OnTextViewChanged(TextView oldTextView, TextView newTextView) { - if (ChangeWatcher == null) - ChangeWatcher = new LocalChangeWatcher(); - if (oldTextView != null) { oldTextView.VisualLinesChanged -= VisualLinesChanged; oldTextView.ScrollOffsetChanged -= ScrollOffsetChanged; @@ -82,32 +71,20 @@ namespace ICSharpCode.AvalonEdit.AddIn if (newTextView != null) { newTextView.VisualLinesChanged += VisualLinesChanged; newTextView.ScrollOffsetChanged += ScrollOffsetChanged; - - ITextEditor editor = newTextView.Services.GetService(typeof(ITextEditor)) as ITextEditor; - changeWatcher.UpdateTextEditor(editor); } } - protected override void OnDocumentChanged(TextDocument oldDocument, TextDocument newDocument) - { - if (ChangeWatcher == null) - ChangeWatcher = new LocalChangeWatcher(); - - ITextEditor editor = TextView.Services.GetService(typeof(ITextEditor)) as ITextEditor; - changeWatcher.UpdateTextEditor(editor); - } - - void VisualLinesChanged(object sender, EventArgs e) + void ChangeOccurred(object sender, EventArgs e) { InvalidateVisual(); } - void ScrollOffsetChanged(object sender, EventArgs e) + void VisualLinesChanged(object sender, EventArgs e) { InvalidateVisual(); } - void ChangeOccured(object sender, EventArgs e) + void ScrollOffsetChanged(object sender, EventArgs e) { InvalidateVisual(); } @@ -124,7 +101,7 @@ namespace ICSharpCode.AvalonEdit.AddIn if (!disposed) { OnTextViewChanged(TextView, null); changeWatcher.Dispose(); - ChangeWatcher = null; + changeWatcher = null; disposed = true; } } @@ -132,95 +109,157 @@ namespace ICSharpCode.AvalonEdit.AddIn public interface IChangeWatcher : IDisposable { - event EventHandler ChangeOccured; + event EventHandler ChangeOccurred; ChangeType GetChange(IDocumentLine line); - void UpdateTextEditor(ITextEditor editor); + void Initialize(IDocument document); } - public enum ChangeType : int + public enum ChangeType { - None = 0x0000, - Added = 0x0001, - Deleted = 0x0002, - Modified = 0x0004, - /// - /// Only to be used by LocalChangeWatcher. States if a change is unsaved or not. - /// - Saved = 0x0008, - /// - /// Only to be used by LocalChangeWatcher. States if a change is unsaved or not. - /// - Unsaved = 0x0016 + None, + Added, + Modified, + Unsaved } - public class LocalChangeWatcher : IChangeWatcher, ILineTracker + public class DefaultChangeWatcher : IChangeWatcher, ILineTracker { + struct LineChangeInfo : IEquatable + { + ChangeType change; + + 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 static bool operator !=(DefaultChangeWatcher.LineChangeInfo lhs, DefaultChangeWatcher.LineChangeInfo rhs) + { + return !(lhs == rhs); + } + #endregion + } + WeakLineTracker lineTracker; - List changedLines; - List lastSavedChangedLines; - bool changed; - OpenedFile openedFile; - TextView textView; - ITextEditor editor; + CompressingTreeList changeList; + TextDocument document; - public event EventHandler ChangeOccured; + public event EventHandler ChangeOccurred; - protected void OnChangeOccured(EventArgs e) + protected void OnChangeOccurred(EventArgs e) { - if (ChangeOccured != null) { - ChangeOccured(this, e); + if (ChangeOccurred != null) { + ChangeOccurred(this, e); } } public ChangeType GetChange(IDocumentLine line) { - if (openedFile == null && editor.FileName != null) { - openedFile = FileService.GetOpenedFile(editor.FileName); - openedFile.IsDirtyChanged += IsDirtyChanged; - } + return changeList[line.LineNumber].Change; + } + + public void Initialize(IDocument document) + { + if (this.document != null) + return; - DocumentLine documentLine = textView.Document.GetLineByNumber(line.LineNumber); + this.document = ((TextView)document.GetService(typeof(TextView))).Document; + this.changeList = new CompressingTreeList((x, y) => x.Equals(y)); - if (lastSavedChangedLines.Contains(documentLine)) - return ChangeType.Saved; - if (changedLines.Contains(documentLine)) - return ChangeType.Unsaved; + SetupInitialFileState(); - 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) { - lastSavedChangedLines = lastSavedChangedLines.Concat(changedLines).Distinct().ToList(); - changedLines.Clear(); - changed = false; - OnChangeOccured(EventArgs.Empty); - } + changeList.Clear(); + changeList.InsertRange(0, this.document.LineCount + 1, new LineChangeInfo(ChangeType.None, "")); + OnChangeOccurred(EventArgs.Empty); + } + + void UndoStackPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (document.UndoStack.IsOriginalFile) + SetupInitialFileState(); } void ILineTracker.BeforeRemoveLine(DocumentLine line) { - changedLines.Remove(line); - lastSavedChangedLines.Remove(line); - changed = true; + int index = line.LineNumber; + LineChangeInfo info = changeList[index]; + 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) { - if (!changedLines.Contains(line)) - changedLines.Add(line); - lastSavedChangedLines.Remove(line); - changed = true; + int index = line.LineNumber; + var info = changeList[index]; + info.Change = ChangeType.Unsaved; + changeList[index] = info; } void ILineTracker.LineInserted(DocumentLine insertionPos, DocumentLine newLine) { - if (!changedLines.Contains(insertionPos)) - changedLines.Add(insertionPos); - lastSavedChangedLines.Remove(insertionPos); - changedLines.Add(newLine); - changed = true; + int index = insertionPos.LineNumber; + var firstLine = changeList[index]; + var newLineInfo = new LineChangeInfo(ChangeType.Unsaved, firstLine.DeletedLinesAfterThisLine); + + firstLine.Change = ChangeType.Unsaved; + firstLine.DeletedLinesAfterThisLine = ""; + + changeList.Insert(index + 1, newLineInfo); + changeList[index] = firstLine; } void ILineTracker.RebuildDocument() @@ -233,36 +272,9 @@ namespace ICSharpCode.AvalonEdit.AddIn { if (!disposed) { lineTracker.Deregister(); - openedFile.IsDirtyChanged -= IsDirtyChanged; - FileService.FileCreated -= FileServiceFileCreated; + this.document.UndoStack.PropertyChanged -= UndoStackPropertyChanged; 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(); - lastSavedChangedLines = new List(); - } - - void FileServiceFileCreated(object sender, FileEventArgs e) - { - - } } }