From c90c75fa7981adb9e2fdbec93d00b6501287c733 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 23 Dec 2010 21:46:27 +0100 Subject: [PATCH] Use only one ChangeWatcher instance in split view. --- .../Src/ChangeMarkerMargin.cs | 37 ++++++++----------- .../AvalonEdit.AddIn/Src/CodeEditor.cs | 12 ++++-- .../Src/DefaultChangeWatcher.cs | 17 ++++----- .../AvalonEdit.AddIn/Src/IconBarMargin.cs | 7 +++- .../AvalonEdit.AddIn/Src/LineChangeInfo.cs | 5 ++- .../Src/MyersDiff/DocumentSequence.cs | 2 + 6 files changed, 43 insertions(+), 37 deletions(-) diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs index 68fb9c81dc..03401ab0a0 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs @@ -19,10 +19,20 @@ namespace ICSharpCode.AvalonEdit.AddIn { IChangeWatcher changeWatcher; - public ChangeMarkerMargin() + public ChangeMarkerMargin(IChangeWatcher changeWatcher) { - changeWatcher = new DefaultChangeWatcher(); - changeWatcher.ChangeOccurred += new EventHandler(ChangeOccurred); + this.changeWatcher = changeWatcher; + changeWatcher.ChangeOccurred += ChangeOccurred; + } + + bool disposed = false; + + public void Dispose() + { + if (!disposed) { + changeWatcher.ChangeOccurred -= ChangeOccurred; + disposed = true; + } } protected override void OnRender(DrawingContext drawingContext) @@ -31,13 +41,10 @@ namespace ICSharpCode.AvalonEdit.AddIn TextView textView = this.TextView; 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, 5, line.Height); - LineChangeInfo info = changeWatcher.GetChange(editor.Document.GetLine(line.FirstDocumentLine.LineNumber)); + LineChangeInfo info = changeWatcher.GetChange(line.FirstDocumentLine.LineNumber); switch (info.Change) { case ChangeType.None: @@ -65,7 +72,7 @@ namespace ICSharpCode.AvalonEdit.AddIn // special case for line 0 if (line.FirstDocumentLine.LineNumber == 1) { - info = changeWatcher.GetChange(null); + info = changeWatcher.GetChange(0); if (!string.IsNullOrEmpty(info.DeletedLinesAfterThisLine)) { Point pt1 = new Point(5, line.VisualTop - textView.ScrollOffset.Y - 4); @@ -97,7 +104,7 @@ namespace ICSharpCode.AvalonEdit.AddIn oldTextView.VisualLinesChanged -= VisualLinesChanged; oldTextView.ScrollOffsetChanged -= ScrollOffsetChanged; } - + base.OnTextViewChanged(oldTextView, newTextView); if (newTextView != null) { newTextView.VisualLinesChanged += VisualLinesChanged; newTextView.ScrollOffsetChanged += ScrollOffsetChanged; @@ -123,17 +130,5 @@ namespace ICSharpCode.AvalonEdit.AddIn { return new Size(5, 0); } - - bool disposed = false; - - public void Dispose() - { - if (!disposed) { - OnTextViewChanged(TextView, null); - changeWatcher.Dispose(); - changeWatcher = null; - disposed = true; - } - } } } \ No newline at end of file diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs index 035773f627..4acc415db9 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs @@ -48,6 +48,7 @@ namespace ICSharpCode.AvalonEdit.AddIn GridSplitter gridSplitter; readonly IconBarManager iconBarManager; readonly TextMarkerService textMarkerService; + readonly IChangeWatcher changeWatcher; ErrorPainter errorPainter; public CodeEditorView PrimaryTextEditor { @@ -116,6 +117,7 @@ namespace ICSharpCode.AvalonEdit.AddIn } else { this.errorPainter.UpdateErrors(); } + changeWatcher.Initialize(this.DocumentAdapter); FetchParseInformation(); } @@ -143,6 +145,7 @@ namespace ICSharpCode.AvalonEdit.AddIn textMarkerService = new TextMarkerService(this); iconBarManager = new IconBarManager(); + changeWatcher = new DefaultChangeWatcher(); primaryTextEditor = CreateTextEditor(); primaryTextEditorAdapter = (CodeEditorAdapter)primaryTextEditor.TextArea.GetService(typeof(ITextEditor)); @@ -175,6 +178,9 @@ namespace ICSharpCode.AvalonEdit.AddIn secondaryTextEditor.UpdateCustomizedHighlighting(); } + /// + /// This method is called to create a new text editor view (=once for the primary editor; and whenever splitting the editor) + /// protected virtual CodeEditorView CreateTextEditor() { CodeEditorView codeEditorView = new CodeEditorView(); @@ -199,7 +205,7 @@ namespace ICSharpCode.AvalonEdit.AddIn textView.Services.AddService(typeof(IBookmarkMargin), iconBarManager); codeEditorView.TextArea.LeftMargins.Insert(0, new IconBarMargin(iconBarManager)); - codeEditorView.TextArea.LeftMargins.Add(new ChangeMarkerMargin()); + codeEditorView.TextArea.LeftMargins.Add(new ChangeMarkerMargin(changeWatcher)); textView.Services.AddService(typeof(ISyntaxHighlighter), new AvalonEditSyntaxHighlighterAdapter(textView)); @@ -221,8 +227,8 @@ namespace ICSharpCode.AvalonEdit.AddIn protected virtual void DisposeTextEditor(CodeEditorView textEditor) { - // detach IconBarMargin from IconBarManager - textEditor.TextArea.LeftMargins.OfType().Single().TextView = null; + foreach (var d in textEditor.TextArea.LeftMargins.OfType()) + d.Dispose(); textEditor.Dispose(); } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DefaultChangeWatcher.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DefaultChangeWatcher.cs index 2916ed7cb8..31bb0361aa 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DefaultChangeWatcher.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DefaultChangeWatcher.cs @@ -20,7 +20,6 @@ namespace ICSharpCode.AvalonEdit.AddIn { public class DefaultChangeWatcher : IChangeWatcher, ILineTracker { - WeakLineTracker lineTracker; CompressingTreeList changeList; IDocument document; TextDocument textDocument; @@ -35,12 +34,9 @@ namespace ICSharpCode.AvalonEdit.AddIn } } - public LineChangeInfo GetChange(IDocumentLine line) + public LineChangeInfo GetChange(int lineNumber) { - if (line == null) - return changeList[0]; - - return changeList[line.LineNumber]; + return changeList[lineNumber]; } public void Initialize(IDocument document) @@ -49,19 +45,20 @@ namespace ICSharpCode.AvalonEdit.AddIn return; this.document = document; - this.textDocument = ((TextView)document.GetService(typeof(TextView))).Document; + this.textDocument = (TextDocument)document.GetService(typeof(TextDocument)); this.changeList = new CompressingTreeList((x, y) => x.Equals(y)); Stream baseFileStream = GetBaseVersion(); // TODO : update baseDocument on VCS actions if (baseFileStream != null) { + // ReadAll() is taking care of closing the stream baseDocument = DocumentUtilitites.LoadReadOnlyDocumentFromBuffer(new StringTextBuffer(ReadAll(baseFileStream))); } SetupInitialFileState(false); - lineTracker = WeakLineTracker.Register(this.textDocument, this); + this.textDocument.LineTrackers.Add(this); this.textDocument.UndoStack.PropertyChanged += UndoStackPropertyChanged; } @@ -144,7 +141,7 @@ namespace ICSharpCode.AvalonEdit.AddIn void UndoStackPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (textDocument.UndoStack.IsOriginalFile) + if (e.PropertyName == "IsOriginalFile" && textDocument.UndoStack.IsOriginalFile) SetupInitialFileState(true); } @@ -185,7 +182,7 @@ namespace ICSharpCode.AvalonEdit.AddIn public void Dispose() { if (!disposed) { - lineTracker.Deregister(); + this.textDocument.LineTrackers.Remove(this); this.textDocument.UndoStack.PropertyChanged -= UndoStackPropertyChanged; disposed = true; } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs index 28d34e8ead..aa17b024ec 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs @@ -18,7 +18,7 @@ namespace ICSharpCode.AvalonEdit.AddIn /// /// Icon bar: contains breakpoints and other icons. /// - public class IconBarMargin : AbstractMargin + public class IconBarMargin : AbstractMargin, IDisposable { readonly IconBarManager manager; @@ -49,6 +49,11 @@ namespace ICSharpCode.AvalonEdit.AddIn { InvalidateVisual(); } + + public virtual void Dispose() + { + this.TextView = null; // detach from TextView (will also detach from manager) + } #endregion /// diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/LineChangeInfo.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/LineChangeInfo.cs index 855c79481e..b9e3e4755f 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/LineChangeInfo.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/LineChangeInfo.cs @@ -9,11 +9,12 @@ namespace ICSharpCode.AvalonEdit.AddIn public interface IChangeWatcher : IDisposable { event EventHandler ChangeOccurred; + /// /// Returns the change information for a given line. - /// Pass null to get the changes before the first line. + /// Pass 0 to get the changes before the first line. /// - LineChangeInfo GetChange(IDocumentLine line); + LineChangeInfo GetChange(int lineNumber); void Initialize(IDocument document); } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/MyersDiff/DocumentSequence.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/MyersDiff/DocumentSequence.cs index 3c768d404a..89f8850197 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/MyersDiff/DocumentSequence.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/MyersDiff/DocumentSequence.cs @@ -15,6 +15,8 @@ namespace ICSharpCode.AvalonEdit.AddIn.MyersDiff { this.hashes = new int[document.TotalNumberOfLines]; + // Construct a perfect hash for the document lines, and store the 'hash code' + // (really just a unique identifier for each line content) in our array. for (int i = 1; i <= document.TotalNumberOfLines; i++) { string text = document.GetLine(i).Text; int hash;