Browse Source

Use only one ChangeWatcher instance in split view.

pull/15/head
Daniel Grunwald 15 years ago
parent
commit
c90c75fa79
  1. 37
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs
  2. 12
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  3. 17
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DefaultChangeWatcher.cs
  4. 7
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs
  5. 5
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/LineChangeInfo.cs
  6. 2
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/MyersDiff/DocumentSequence.cs

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

@ -19,10 +19,20 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
IChangeWatcher changeWatcher; IChangeWatcher changeWatcher;
public ChangeMarkerMargin() public ChangeMarkerMargin(IChangeWatcher changeWatcher)
{ {
changeWatcher = new DefaultChangeWatcher(); this.changeWatcher = changeWatcher;
changeWatcher.ChangeOccurred += new EventHandler(ChangeOccurred); changeWatcher.ChangeOccurred += ChangeOccurred;
}
bool disposed = false;
public void Dispose()
{
if (!disposed) {
changeWatcher.ChangeOccurred -= ChangeOccurred;
disposed = true;
}
} }
protected override void OnRender(DrawingContext drawingContext) protected override void OnRender(DrawingContext drawingContext)
@ -31,13 +41,10 @@ namespace ICSharpCode.AvalonEdit.AddIn
TextView textView = this.TextView; TextView textView = this.TextView;
if (textView != null && textView.VisualLinesValid) { if (textView != null && textView.VisualLinesValid) {
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, 5, line.Height); 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) { switch (info.Change) {
case ChangeType.None: case ChangeType.None:
@ -65,7 +72,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
// special case for line 0 // special case for line 0
if (line.FirstDocumentLine.LineNumber == 1) { if (line.FirstDocumentLine.LineNumber == 1) {
info = changeWatcher.GetChange(null); info = changeWatcher.GetChange(0);
if (!string.IsNullOrEmpty(info.DeletedLinesAfterThisLine)) { if (!string.IsNullOrEmpty(info.DeletedLinesAfterThisLine)) {
Point pt1 = new Point(5, line.VisualTop - textView.ScrollOffset.Y - 4); Point pt1 = new Point(5, line.VisualTop - textView.ScrollOffset.Y - 4);
@ -97,7 +104,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
oldTextView.VisualLinesChanged -= VisualLinesChanged; oldTextView.VisualLinesChanged -= VisualLinesChanged;
oldTextView.ScrollOffsetChanged -= ScrollOffsetChanged; oldTextView.ScrollOffsetChanged -= ScrollOffsetChanged;
} }
base.OnTextViewChanged(oldTextView, newTextView);
if (newTextView != null) { if (newTextView != null) {
newTextView.VisualLinesChanged += VisualLinesChanged; newTextView.VisualLinesChanged += VisualLinesChanged;
newTextView.ScrollOffsetChanged += ScrollOffsetChanged; newTextView.ScrollOffsetChanged += ScrollOffsetChanged;
@ -123,17 +130,5 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
return new Size(5, 0); return new Size(5, 0);
} }
bool disposed = false;
public void Dispose()
{
if (!disposed) {
OnTextViewChanged(TextView, null);
changeWatcher.Dispose();
changeWatcher = null;
disposed = true;
}
}
} }
} }

12
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs

@ -48,6 +48,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
GridSplitter gridSplitter; GridSplitter gridSplitter;
readonly IconBarManager iconBarManager; readonly IconBarManager iconBarManager;
readonly TextMarkerService textMarkerService; readonly TextMarkerService textMarkerService;
readonly IChangeWatcher changeWatcher;
ErrorPainter errorPainter; ErrorPainter errorPainter;
public CodeEditorView PrimaryTextEditor { public CodeEditorView PrimaryTextEditor {
@ -116,6 +117,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
} else { } else {
this.errorPainter.UpdateErrors(); this.errorPainter.UpdateErrors();
} }
changeWatcher.Initialize(this.DocumentAdapter);
FetchParseInformation(); FetchParseInformation();
} }
@ -143,6 +145,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
textMarkerService = new TextMarkerService(this); textMarkerService = new TextMarkerService(this);
iconBarManager = new IconBarManager(); iconBarManager = new IconBarManager();
changeWatcher = new DefaultChangeWatcher();
primaryTextEditor = CreateTextEditor(); primaryTextEditor = CreateTextEditor();
primaryTextEditorAdapter = (CodeEditorAdapter)primaryTextEditor.TextArea.GetService(typeof(ITextEditor)); primaryTextEditorAdapter = (CodeEditorAdapter)primaryTextEditor.TextArea.GetService(typeof(ITextEditor));
@ -175,6 +178,9 @@ namespace ICSharpCode.AvalonEdit.AddIn
secondaryTextEditor.UpdateCustomizedHighlighting(); secondaryTextEditor.UpdateCustomizedHighlighting();
} }
/// <summary>
/// This method is called to create a new text editor view (=once for the primary editor; and whenever splitting the editor)
/// </summary>
protected virtual CodeEditorView CreateTextEditor() protected virtual CodeEditorView CreateTextEditor()
{ {
CodeEditorView codeEditorView = new CodeEditorView(); CodeEditorView codeEditorView = new CodeEditorView();
@ -199,7 +205,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
textView.Services.AddService(typeof(IBookmarkMargin), iconBarManager); textView.Services.AddService(typeof(IBookmarkMargin), iconBarManager);
codeEditorView.TextArea.LeftMargins.Insert(0, new IconBarMargin(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)); textView.Services.AddService(typeof(ISyntaxHighlighter), new AvalonEditSyntaxHighlighterAdapter(textView));
@ -221,8 +227,8 @@ namespace ICSharpCode.AvalonEdit.AddIn
protected virtual void DisposeTextEditor(CodeEditorView textEditor) protected virtual void DisposeTextEditor(CodeEditorView textEditor)
{ {
// detach IconBarMargin from IconBarManager foreach (var d in textEditor.TextArea.LeftMargins.OfType<IDisposable>())
textEditor.TextArea.LeftMargins.OfType<IconBarMargin>().Single().TextView = null; d.Dispose();
textEditor.Dispose(); textEditor.Dispose();
} }

17
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DefaultChangeWatcher.cs

@ -20,7 +20,6 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
public class DefaultChangeWatcher : IChangeWatcher, ILineTracker public class DefaultChangeWatcher : IChangeWatcher, ILineTracker
{ {
WeakLineTracker lineTracker;
CompressingTreeList<LineChangeInfo> changeList; CompressingTreeList<LineChangeInfo> changeList;
IDocument document; IDocument document;
TextDocument textDocument; 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[lineNumber];
return changeList[0];
return changeList[line.LineNumber];
} }
public void Initialize(IDocument document) public void Initialize(IDocument document)
@ -49,19 +45,20 @@ namespace ICSharpCode.AvalonEdit.AddIn
return; return;
this.document = document; this.document = document;
this.textDocument = ((TextView)document.GetService(typeof(TextView))).Document; this.textDocument = (TextDocument)document.GetService(typeof(TextDocument));
this.changeList = new CompressingTreeList<LineChangeInfo>((x, y) => x.Equals(y)); this.changeList = new CompressingTreeList<LineChangeInfo>((x, y) => x.Equals(y));
Stream baseFileStream = GetBaseVersion(); Stream baseFileStream = GetBaseVersion();
// TODO : update baseDocument on VCS actions // TODO : update baseDocument on VCS actions
if (baseFileStream != null) { if (baseFileStream != null) {
// ReadAll() is taking care of closing the stream
baseDocument = DocumentUtilitites.LoadReadOnlyDocumentFromBuffer(new StringTextBuffer(ReadAll(baseFileStream))); baseDocument = DocumentUtilitites.LoadReadOnlyDocumentFromBuffer(new StringTextBuffer(ReadAll(baseFileStream)));
} }
SetupInitialFileState(false); SetupInitialFileState(false);
lineTracker = WeakLineTracker.Register(this.textDocument, this); this.textDocument.LineTrackers.Add(this);
this.textDocument.UndoStack.PropertyChanged += UndoStackPropertyChanged; this.textDocument.UndoStack.PropertyChanged += UndoStackPropertyChanged;
} }
@ -144,7 +141,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
void UndoStackPropertyChanged(object sender, PropertyChangedEventArgs e) void UndoStackPropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (textDocument.UndoStack.IsOriginalFile) if (e.PropertyName == "IsOriginalFile" && textDocument.UndoStack.IsOriginalFile)
SetupInitialFileState(true); SetupInitialFileState(true);
} }
@ -185,7 +182,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
public void Dispose() public void Dispose()
{ {
if (!disposed) { if (!disposed) {
lineTracker.Deregister(); this.textDocument.LineTrackers.Remove(this);
this.textDocument.UndoStack.PropertyChanged -= UndoStackPropertyChanged; this.textDocument.UndoStack.PropertyChanged -= UndoStackPropertyChanged;
disposed = true; disposed = true;
} }

7
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs

@ -18,7 +18,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
/// <summary> /// <summary>
/// Icon bar: contains breakpoints and other icons. /// Icon bar: contains breakpoints and other icons.
/// </summary> /// </summary>
public class IconBarMargin : AbstractMargin public class IconBarMargin : AbstractMargin, IDisposable
{ {
readonly IconBarManager manager; readonly IconBarManager manager;
@ -49,6 +49,11 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
InvalidateVisual(); InvalidateVisual();
} }
public virtual void Dispose()
{
this.TextView = null; // detach from TextView (will also detach from manager)
}
#endregion #endregion
/// <inheritdoc/> /// <inheritdoc/>

5
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/LineChangeInfo.cs

@ -9,11 +9,12 @@ namespace ICSharpCode.AvalonEdit.AddIn
public interface IChangeWatcher : IDisposable public interface IChangeWatcher : IDisposable
{ {
event EventHandler ChangeOccurred; event EventHandler ChangeOccurred;
/// <summary> /// <summary>
/// Returns the change information for a given line. /// 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.
/// </summary> /// </summary>
LineChangeInfo GetChange(IDocumentLine line); LineChangeInfo GetChange(int lineNumber);
void Initialize(IDocument document); void Initialize(IDocument document);
} }

2
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/MyersDiff/DocumentSequence.cs

@ -15,6 +15,8 @@ namespace ICSharpCode.AvalonEdit.AddIn.MyersDiff
{ {
this.hashes = new int[document.TotalNumberOfLines]; 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++) { for (int i = 1; i <= document.TotalNumberOfLines; i++) {
string text = document.GetLine(i).Text; string text = document.GetLine(i).Text;
int hash; int hash;

Loading…
Cancel
Save