31 changed files with 288 additions and 214 deletions
@ -0,0 +1,104 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Specialized; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Dom |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// A model collection that filters an input collection.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FilterModelCollection<T> : IModelCollection<T> |
||||||
|
{ |
||||||
|
readonly IModelCollection<T> input; |
||||||
|
readonly Func<T, bool> predicate; |
||||||
|
bool isAttached; |
||||||
|
NotifyCollectionChangedEventHandler collectionChanged; |
||||||
|
|
||||||
|
public FilterModelCollection(IModelCollection<T> input, Func<T, bool> predicate) |
||||||
|
{ |
||||||
|
if (input == null) |
||||||
|
throw new ArgumentNullException("input"); |
||||||
|
if (predicate == null) |
||||||
|
throw new ArgumentNullException("predicate"); |
||||||
|
this.input = input; |
||||||
|
this.predicate = predicate; |
||||||
|
} |
||||||
|
|
||||||
|
public event NotifyCollectionChangedEventHandler CollectionChanged { |
||||||
|
add { |
||||||
|
collectionChanged += value; |
||||||
|
if (collectionChanged != null && !isAttached) { |
||||||
|
input.CollectionChanged += input_CollectionChanged; |
||||||
|
isAttached = true; |
||||||
|
} |
||||||
|
} |
||||||
|
remove { |
||||||
|
collectionChanged -= value; |
||||||
|
if (collectionChanged == null && isAttached) { |
||||||
|
input.CollectionChanged -= input_CollectionChanged; |
||||||
|
isAttached = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void input_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||||
|
{ |
||||||
|
switch (e.Action) { |
||||||
|
case NotifyCollectionChangedAction.Add: |
||||||
|
collectionChanged(this, new NotifyCollectionChangedEventArgs( |
||||||
|
NotifyCollectionChangedAction.Add, ApplyFilter(e.NewItems))); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Remove: |
||||||
|
collectionChanged(this, new NotifyCollectionChangedEventArgs( |
||||||
|
NotifyCollectionChangedAction.Remove, ApplyFilter(e.OldItems))); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Replace: |
||||||
|
collectionChanged(this, new NotifyCollectionChangedEventArgs( |
||||||
|
NotifyCollectionChangedAction.Replace, ApplyFilter(e.OldItems), ApplyFilter(e.NewItems))); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Move: |
||||||
|
// this collection is unordered
|
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Reset: |
||||||
|
collectionChanged(this, new NotifyCollectionChangedEventArgs( |
||||||
|
NotifyCollectionChangedAction.Reset)); |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new NotSupportedException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
IList ApplyFilter(IList inputItems) |
||||||
|
{ |
||||||
|
if (inputItems == null) |
||||||
|
return null; |
||||||
|
List<T> outputItems = new List<T>(); |
||||||
|
foreach (T item in inputItems) { |
||||||
|
if (predicate(item)) |
||||||
|
outputItems.Add(item); |
||||||
|
} |
||||||
|
return outputItems; |
||||||
|
} |
||||||
|
|
||||||
|
public int Count { |
||||||
|
get { |
||||||
|
return input.Count(predicate); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator() |
||||||
|
{ |
||||||
|
return input.Where(predicate).GetEnumerator(); |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() |
||||||
|
{ |
||||||
|
return GetEnumerator(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.ObjectModel; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Dom |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// A model collection implementation that is based on a ObservableCollection.
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleModelCollection<T> : ObservableCollection<T>, IModelCollection<T> |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using ICSharpCode.SharpDevelop.Editor; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Editor.Bookmarks |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// The bookmark margin.
|
||||||
|
/// </summary>
|
||||||
|
[DocumentService] |
||||||
|
public interface IBookmarkMargin |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of bookmarks.
|
||||||
|
/// </summary>
|
||||||
|
IList<IBookmark> Bookmarks { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Redraws the bookmark margin. Bookmarks need to call this method when the Image changes.
|
||||||
|
/// </summary>
|
||||||
|
void Redraw(); |
||||||
|
|
||||||
|
event EventHandler RedrawRequested; |
||||||
|
} |
||||||
|
} |
@ -1,123 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.ComponentModel; |
|
||||||
using System.Globalization; |
|
||||||
using System.Text; |
|
||||||
using System.Windows; |
|
||||||
using ICSharpCode.Core; |
|
||||||
using ICSharpCode.NRefactory; |
|
||||||
|
|
||||||
namespace ICSharpCode.SharpDevelop.Bookmarks |
|
||||||
{ |
|
||||||
public sealed class BookmarkConverter : TypeConverter |
|
||||||
{ |
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) |
|
||||||
{ |
|
||||||
if (sourceType == typeof(string)) { |
|
||||||
return true; |
|
||||||
} else { |
|
||||||
return base.CanConvertFrom(context, sourceType); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
|
||||||
{ |
|
||||||
if (value is string) { |
|
||||||
string[] v = ((string)value).Split('|'); |
|
||||||
|
|
||||||
FileName fileName = FileName.Create(v[1]); |
|
||||||
int lineNumber = int.Parse(v[2], culture); |
|
||||||
int columnNumber = int.Parse(v[3], culture); |
|
||||||
if (lineNumber < 0) |
|
||||||
return null; |
|
||||||
if (columnNumber < 0) |
|
||||||
return null; |
|
||||||
SDBookmark bookmark; |
|
||||||
switch (v[0]) { |
|
||||||
case "Breakpoint": |
|
||||||
Debugging.BreakpointAction action = Debugging.BreakpointAction.Break; |
|
||||||
string scriptLanguage = ""; |
|
||||||
string script = ""; |
|
||||||
action = (Debugging.BreakpointAction)Enum.Parse(typeof(Debugging.BreakpointAction), v[5]); |
|
||||||
scriptLanguage = v[6]; |
|
||||||
script = v[7]; |
|
||||||
|
|
||||||
var bbm = new Debugging.BreakpointBookmark(fileName, new TextLocation(lineNumber, columnNumber), action, scriptLanguage, script); |
|
||||||
bbm.IsEnabled = bool.Parse(v[4]); |
|
||||||
bbm.Action = action; |
|
||||||
bbm.ScriptLanguage = scriptLanguage; |
|
||||||
bbm.Condition = script; |
|
||||||
bookmark = bbm; |
|
||||||
break; |
|
||||||
case "DecompiledBreakpointBookmark": |
|
||||||
action = (Debugging.BreakpointAction)Enum.Parse(typeof(Debugging.BreakpointAction), v[5]); |
|
||||||
scriptLanguage = v[6]; |
|
||||||
script = v[7]; |
|
||||||
|
|
||||||
bbm = new DecompiledBreakpointBookmark(fileName, new TextLocation(columnNumber, lineNumber), action, scriptLanguage, script); |
|
||||||
bbm.IsEnabled = bool.Parse(v[4]); |
|
||||||
bbm.Action = action; |
|
||||||
bbm.ScriptLanguage = scriptLanguage; |
|
||||||
bbm.Condition = script; |
|
||||||
bookmark = bbm; |
|
||||||
break; |
|
||||||
default: |
|
||||||
bookmark = new Bookmark(fileName, new TextLocation(lineNumber, columnNumber)); |
|
||||||
break; |
|
||||||
} |
|
||||||
return bookmark; |
|
||||||
} else { |
|
||||||
return base.ConvertFrom(context, culture, value); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) |
|
||||||
{ |
|
||||||
SDBookmark bookmark = value as SDBookmark; |
|
||||||
if (destinationType == typeof(string) && bookmark != null) { |
|
||||||
StringBuilder b = new StringBuilder(); |
|
||||||
if (bookmark is DecompiledBreakpointBookmark) { |
|
||||||
b.Append("DecompiledBreakpointBookmark"); |
|
||||||
} else if (bookmark is Debugging.BreakpointBookmark) { |
|
||||||
b.Append("Breakpoint"); |
|
||||||
} else { |
|
||||||
b.Append("Bookmark"); |
|
||||||
} |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bookmark.FileName); |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bookmark.LineNumber); |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bookmark.ColumnNumber); |
|
||||||
|
|
||||||
if (bookmark is DecompiledBreakpointBookmark) { |
|
||||||
var bbm = (DecompiledBreakpointBookmark)bookmark; |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bbm.IsEnabled.ToString()); |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bbm.Action.ToString()); |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bbm.ScriptLanguage); |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bbm.Condition); |
|
||||||
} else if (bookmark is Debugging.BreakpointBookmark) { |
|
||||||
var bbm = (Debugging.BreakpointBookmark)bookmark; |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bbm.IsEnabled.ToString()); |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bbm.Action.ToString()); |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bbm.ScriptLanguage); |
|
||||||
b.Append('|'); |
|
||||||
b.Append(bbm.Condition); |
|
||||||
} |
|
||||||
|
|
||||||
return b.ToString(); |
|
||||||
} else { |
|
||||||
return base.ConvertTo(context, culture, value, destinationType); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,68 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Specialized; |
||||||
|
using System.Linq; |
||||||
|
using ICSharpCode.SharpDevelop.Dom; |
||||||
|
using NUnit.Framework; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Utils |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Checks the change events of a model collection for consistency
|
||||||
|
/// with the collection data.
|
||||||
|
/// </summary>
|
||||||
|
public class ModelCollectionEventCheck<T> |
||||||
|
{ |
||||||
|
readonly IModelCollection<T> modelCollection; |
||||||
|
List<T> list; |
||||||
|
|
||||||
|
public ModelCollectionEventCheck(IModelCollection<T> modelCollection) |
||||||
|
{ |
||||||
|
if (modelCollection == null) |
||||||
|
throw new ArgumentNullException("modelCollection"); |
||||||
|
this.modelCollection = modelCollection; |
||||||
|
this.list = new List<T>(modelCollection); |
||||||
|
modelCollection.CollectionChanged += OnCollectionChanged; |
||||||
|
} |
||||||
|
|
||||||
|
void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||||
|
{ |
||||||
|
switch (e.Action) { |
||||||
|
case NotifyCollectionChangedAction.Add: |
||||||
|
list.InsertRange(e.NewStartingIndex, e.NewItems.Cast<T>()); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Remove: |
||||||
|
Assert.AreEqual(list.GetRange(e.OldStartingIndex, e.OldItems.Count), e.OldItems); |
||||||
|
list.RemoveRange(e.OldStartingIndex, e.OldItems.Count); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Replace: |
||||||
|
Assert.AreEqual(e.OldStartingIndex, e.NewStartingIndex, "Old and new starting index must be identical for replace action"); |
||||||
|
Assert.AreEqual(list.GetRange(e.OldStartingIndex, e.OldItems.Count), e.OldItems); |
||||||
|
list.RemoveRange(e.OldStartingIndex, e.OldItems.Count); |
||||||
|
list.InsertRange(e.NewStartingIndex, e.NewItems.Cast<T>()); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Move: |
||||||
|
Assert.AreEqual(e.OldItems, e.NewItems); |
||||||
|
Assert.AreEqual(list.GetRange(e.OldStartingIndex, e.OldItems.Count), e.OldItems); |
||||||
|
list.RemoveRange(e.OldStartingIndex, e.OldItems.Count); |
||||||
|
list.InsertRange(e.NewStartingIndex, e.NewItems.Cast<T>()); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Reset: |
||||||
|
list.Clear(); |
||||||
|
list.AddRange(modelCollection); |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new Exception("Invalid value for NotifyCollectionChangedAction"); |
||||||
|
} |
||||||
|
Verify(); |
||||||
|
} |
||||||
|
|
||||||
|
public void Verify() |
||||||
|
{ |
||||||
|
Assert.AreEqual(list, modelCollection.ToList()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue