Browse Source

created ChangeWatcher API: allows display of changes from different data sources (changes while file is opened, Git/SVN diff, etc.)

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

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

@ -8,6 +8,7 @@ using System.Windows; @@ -8,6 +8,7 @@ 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.SharpDevelop.Editor;
@ -17,19 +18,19 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -17,19 +18,19 @@ namespace ICSharpCode.AvalonEdit.AddIn
/// <summary>
/// Description of ChangeMarkerMargin.
/// </summary>
public class ChangeMarkerMargin : AbstractMargin, ILineTracker, IDisposable
public class ChangeMarkerMargin : AbstractMargin, IDisposable
{
WeakLineTracker lineTracker;
List<DocumentLine> changedLines;
List<DocumentLine> lastSavedChangedLines;
bool changed;
OpenedFile openedFile;
IChangeWatcher changeWatcher;
public ChangeMarkerMargin()
{
changedLines = new List<DocumentLine>();
lastSavedChangedLines = new List<DocumentLine>();
changed = false;
public IChangeWatcher ChangeWatcher {
get { return changeWatcher; }
set {
if (changeWatcher != null)
changeWatcher.ChangeOccured -= ChangeOccured;
changeWatcher = value;
if (changeWatcher != null)
changeWatcher.ChangeOccured += ChangeOccured;
}
}
protected override void OnRender(DrawingContext drawingContext)
@ -39,73 +40,191 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -39,73 +40,191 @@ namespace ICSharpCode.AvalonEdit.AddIn
if (textView != null && textView.VisualLinesValid) {
ITextEditor editor = textView.Services.GetService(typeof(ITextEditor)) as ITextEditor;
openedFile = FileService.GetOpenedFile(editor.FileName);
openedFile.IsDirtyChanged += IsDirtyChanged;
textView.ScrollOffsetChanged += ScrollOffsetChanged;
if (lineTracker == null)
lineTracker = WeakLineTracker.Register(textView.Document, this);
foreach (VisualLine line in textView.VisualLines) {
Rect rect = new Rect(0, line.VisualTop - textView.ScrollOffset.Y, renderSize.Width, line.Height);
if (lastSavedChangedLines.Contains(line.FirstDocumentLine))
drawingContext.DrawRectangle(Brushes.LightGreen, null, rect);
else if (changedLines.Contains(line.FirstDocumentLine))
drawingContext.DrawRectangle(Brushes.Yellow, null, rect);
ChangeType type = changeWatcher.GetChange(editor.Document.GetLine(line.FirstDocumentLine.LineNumber));
switch (type) {
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;
case ChangeType.Unsaved:
drawingContext.DrawRectangle(Brushes.Yellow, null, rect);
break;
default:
throw new Exception("Invalid value for ChangeType");
}
}
}
}
protected override void OnTextViewChanged(TextView oldTextView, TextView newTextView)
{
if (ChangeWatcher == null)
ChangeWatcher = new LocalChangeWatcher();
if (oldTextView != null) {
oldTextView.VisualLinesChanged -= VisualLinesChanged;
oldTextView.ScrollOffsetChanged -= ScrollOffsetChanged;
}
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)
{
InvalidateVisual();
}
void ScrollOffsetChanged(object sender, EventArgs e)
{
InvalidateVisual();
}
void ChangeOccured(object sender, EventArgs e)
{
InvalidateVisual();
}
protected override Size MeasureOverride(Size availableSize)
{
return new Size(5, 0);
}
bool disposed = false;
public void Dispose()
{
if (!disposed) {
OnTextViewChanged(TextView, null);
changeWatcher.Dispose();
ChangeWatcher = null;
disposed = true;
}
}
}
public interface IChangeWatcher : IDisposable
{
event EventHandler ChangeOccured;
ChangeType GetChange(IDocumentLine line);
void UpdateTextEditor(ITextEditor editor);
}
public enum ChangeType : int
{
None = 0x0000,
Added = 0x0001,
Deleted = 0x0002,
Modified = 0x0004,
/// <summary>
/// Only to be used by LocalChangeWatcher. States if a change is unsaved or not.
/// </summary>
Saved = 0x0008,
/// <summary>
/// Only to be used by LocalChangeWatcher. States if a change is unsaved or not.
/// </summary>
Unsaved = 0x0016
}
public class LocalChangeWatcher : IChangeWatcher, ILineTracker
{
WeakLineTracker lineTracker;
List<DocumentLine> changedLines;
List<DocumentLine> lastSavedChangedLines;
bool changed;
OpenedFile openedFile;
TextView textView;
ITextEditor editor;
public event EventHandler ChangeOccured;
protected void OnChangeOccured(EventArgs e)
{
if (ChangeOccured != null) {
ChangeOccured(this, e);
}
}
public ChangeType GetChange(IDocumentLine line)
{
if (openedFile == null && editor.FileName != null) {
openedFile = FileService.GetOpenedFile(editor.FileName);
openedFile.IsDirtyChanged += IsDirtyChanged;
}
DocumentLine documentLine = textView.Document.GetLineByNumber(line.LineNumber);
if (lastSavedChangedLines.Contains(documentLine))
return ChangeType.Saved;
if (changedLines.Contains(documentLine))
return ChangeType.Unsaved;
return ChangeType.None;
}
void IsDirtyChanged(object sender, EventArgs e)
{
if (changed && !openedFile.IsDirty) {
lastSavedChangedLines = lastSavedChangedLines.Concat(changedLines).Distinct().ToList();
changedLines.Clear();
changed = false;
InvalidateVisual();
OnChangeOccured(EventArgs.Empty);
}
}
protected override Size MeasureOverride(Size availableSize)
{
return new Size(5, 0);
}
public void BeforeRemoveLine(DocumentLine line)
void ILineTracker.BeforeRemoveLine(DocumentLine line)
{
changedLines.Remove(line);
lastSavedChangedLines.Remove(line);
changed = true;
InvalidateVisual();
}
public void SetLineLength(DocumentLine line, int newTotalLength)
void ILineTracker.SetLineLength(DocumentLine line, int newTotalLength)
{
if (!changedLines.Contains(line))
changedLines.Add(line);
lastSavedChangedLines.Remove(line);
changed = true;
InvalidateVisual();
}
public void LineInserted(DocumentLine insertionPos, DocumentLine newLine)
void ILineTracker.LineInserted(DocumentLine insertionPos, DocumentLine newLine)
{
if (!changedLines.Contains(insertionPos))
changedLines.Add(insertionPos);
lastSavedChangedLines.Remove(insertionPos);
changedLines.Add(newLine);
changed = true;
InvalidateVisual();
}
public void RebuildDocument()
void ILineTracker.RebuildDocument()
{
InvalidateVisual();
}
bool disposed = false;
@ -115,8 +234,35 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -115,8 +234,35 @@ namespace ICSharpCode.AvalonEdit.AddIn
if (!disposed) {
lineTracker.Deregister();
openedFile.IsDirtyChanged -= IsDirtyChanged;
FileService.FileCreated -= FileServiceFileCreated;
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