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 @@ @@ -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 @@ -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 @@ -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 @@ -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 @@ -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,19 +71,12 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -82,19 +71,12 @@ 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)
void ChangeOccurred(object sender, EventArgs e)
{
if (ChangeWatcher == null)
ChangeWatcher = new LocalChangeWatcher();
ITextEditor editor = TextView.Services.GetService(typeof(ITextEditor)) as ITextEditor;
changeWatcher.UpdateTextEditor(editor);
InvalidateVisual();
}
void VisualLinesChanged(object sender, EventArgs e)
@ -107,11 +89,6 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -107,11 +89,6 @@ namespace ICSharpCode.AvalonEdit.AddIn
InvalidateVisual();
}
void ChangeOccured(object sender, EventArgs e)
{
InvalidateVisual();
}
protected override Size MeasureOverride(Size availableSize)
{
return new Size(5, 0);
@ -124,7 +101,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -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 @@ -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,
/// <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
None,
Added,
Modified,
Unsaved
}
public class DefaultChangeWatcher : IChangeWatcher, ILineTracker
{
struct LineChangeInfo : IEquatable<LineChangeInfo>
{
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 class LocalChangeWatcher : IChangeWatcher, ILineTracker
public static bool operator !=(DefaultChangeWatcher.LineChangeInfo lhs, DefaultChangeWatcher.LineChangeInfo rhs)
{
return !(lhs == rhs);
}
#endregion
}
WeakLineTracker lineTracker;
List<DocumentLine> changedLines;
List<DocumentLine> lastSavedChangedLines;
bool changed;
OpenedFile openedFile;
TextView textView;
ITextEditor editor;
CompressingTreeList<LineChangeInfo> 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;
}
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))
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 @@ -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<DocumentLine>();
lastSavedChangedLines = new List<DocumentLine>();
}
void FileServiceFileCreated(object sender, FileEventArgs e)
{
}
}
}

Loading…
Cancel
Save