// 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; using System.Linq; namespace ICSharpCode.SharpDevelop.Dom { /// /// A that works by concatening multiple /// other model collections. /// public sealed class ConcatModelCollection : IModelCollection { sealed class InputCollection : Collection> { readonly ConcatModelCollection owner; public InputCollection(ConcatModelCollection owner) { this.owner = owner; } protected override void ClearItems() { if (owner.collectionChanged != null) { foreach (var input in Items) { input.CollectionChanged -= owner.OnInputCollectionChanged; } } base.ClearItems(); owner.RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } protected override void InsertItem(int index, IModelCollection item) { if (owner.collectionChanged != null) item.CollectionChanged += owner.OnInputCollectionChanged; base.InsertItem(index, item); owner.RaiseCollectionChanged(new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, item.ToArray(), owner.GetCount(index))); } protected override void RemoveItem(int index) { if (owner.collectionChanged != null) Items[index].CollectionChanged -= owner.OnInputCollectionChanged; var oldItems = Items[index].ToArray(); base.RemoveItem(index); owner.RaiseCollectionChanged(new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, oldItems, owner.GetCount(index))); } protected override void SetItem(int index, IModelCollection item) { RemoveItem(index); InsertItem(index, item); } } InputCollection inputs; public ConcatModelCollection() { this.inputs = new InputCollection(this); } public IList> Inputs { get { return inputs; } } NotifyCollectionChangedEventHandler collectionChanged; public event NotifyCollectionChangedEventHandler CollectionChanged { add { var oldEventHandlers = collectionChanged; collectionChanged += value; if (oldEventHandlers == null && collectionChanged != null) { foreach (var input in inputs) input.CollectionChanged += OnInputCollectionChanged; } } remove { var oldEventHandlers = collectionChanged; collectionChanged -= value; if (oldEventHandlers != null && collectionChanged == null) { foreach (var input in inputs) input.CollectionChanged -= OnInputCollectionChanged; } } } void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e) { if (collectionChanged != null) collectionChanged(this, e); } void OnInputCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { int inputIndex = inputs.IndexOf((IModelCollection)sender); int startIndex = GetCount(inputIndex); NotifyCollectionChangedEventArgs newEventArgs; switch (e.Action) { case NotifyCollectionChangedAction.Add: newEventArgs = new NotifyCollectionChangedEventArgs(e.Action, e.NewItems, startIndex + e.NewStartingIndex); break; case NotifyCollectionChangedAction.Remove: newEventArgs = new NotifyCollectionChangedEventArgs(e.Action, e.OldItems, startIndex + e.OldStartingIndex); break; case NotifyCollectionChangedAction.Replace: newEventArgs = new NotifyCollectionChangedEventArgs(e.Action, e.OldItems, e.NewItems, startIndex + e.OldStartingIndex); break; case NotifyCollectionChangedAction.Move: newEventArgs = new NotifyCollectionChangedEventArgs(e.Action, e.OldItems, startIndex + e.OldStartingIndex, startIndex + e.NewStartingIndex); break; case NotifyCollectionChangedAction.Reset: newEventArgs = new NotifyCollectionChangedEventArgs(e.Action); break; default: throw new NotSupportedException("Invalid value for NotifyCollectionChangedAction"); } collectionChanged(this, newEventArgs); } public int Count { get { return GetCount(inputs.Count); } } int GetCount(int inputIndex) { int count = 0; for (int i = 0; i < inputIndex; i++) { count += inputs[i].Count; } return count; } public IEnumerator GetEnumerator() { return inputs.SelectMany(i => i).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public T this[int index] { get { int inputIndex = 0; while (index >= inputs[inputIndex].Count) { index -= inputs[inputIndex].Count; inputIndex++; } return inputs[inputIndex][index]; } } } }