// 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.ObjectModel;
using System.Collections.Specialized;
namespace ICSharpCode.AvalonEdit.Xml
{
///
/// Collection that presents only some items from the wrapped collection.
/// It implicitely filters object that are not of type T (or derived).
///
public class FilteredCollection: ObservableCollection where TCollection : INotifyCollectionChanged, IList
{
TCollection source;
Predicate condition;
List srcPtrs = new List(); // Index to the original collection
/// Create unbound collection
protected FilteredCollection() {}
/// Wrap the given collection. Items of type other then T are filtered
public FilteredCollection(TCollection source) : this (source, x => true) { }
/// Wrap the given collection. Items of type other then T are filtered. Items not matching the condition are filtered.
public FilteredCollection(TCollection source, Predicate condition)
{
this.source = source;
this.condition = condition;
this.source.CollectionChanged += SourceCollectionChanged;
Reset();
}
void Reset()
{
this.Clear();
srcPtrs.Clear();
for(int i = 0; i < source.Count; i++) {
if (source[i] is T && condition(source[i])) {
this.Add((T)source[i]);
srcPtrs.Add(i);
}
}
}
void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch(e.Action) {
case NotifyCollectionChangedAction.Add:
// Update pointers
for(int i = 0; i < srcPtrs.Count; i++) {
if (srcPtrs[i] >= e.NewStartingIndex) {
srcPtrs[i] += e.NewItems.Count;
}
}
// Find where to add items
int addIndex = srcPtrs.FindIndex(srcPtr => srcPtr >= e.NewStartingIndex);
if (addIndex == -1) addIndex = this.Count;
// Add items to collection
for(int i = 0; i < e.NewItems.Count; i++) {
if (e.NewItems[i] is T && condition(e.NewItems[i])) {
this.InsertItem(addIndex, (T)e.NewItems[i]);
srcPtrs.Insert(addIndex, e.NewStartingIndex + i);
addIndex++;
}
}
break;
case NotifyCollectionChangedAction.Remove:
// Remove the item from our collection
for(int i = 0; i < e.OldItems.Count; i++) {
// Anyone points to the removed item?
int removeIndex = srcPtrs.IndexOf(e.OldStartingIndex + i);
// Remove
if (removeIndex != -1) {
this.RemoveAt(removeIndex);
srcPtrs.RemoveAt(removeIndex);
}
}
// Update pointers
for(int i = 0; i < srcPtrs.Count; i++) {
if (srcPtrs[i] >= e.OldStartingIndex) {
srcPtrs[i] -= e.OldItems.Count;
}
}
break;
case NotifyCollectionChangedAction.Reset:
Reset();
break;
default:
throw new NotSupportedException(e.Action.ToString());
}
}
}
}