#region License Information /* HeuristicLab * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using HeuristicLab.Persistence; namespace HeuristicLab.Collections { [StorableType("615e54ff-d8d3-4360-ba85-6941833cc79a")] [Serializable] public abstract class ObservableKeyedCollection : IObservableKeyedCollection { [Storable] protected Dictionary dict; #region Properties public int Count { get { return dict.Count; } } public IEqualityComparer Comparer { get { return dict.Comparer; } } bool ICollection.IsReadOnly { get { return ((ICollection>)dict).IsReadOnly; } } public TItem this[TKey key] { get { return dict[key]; } } #endregion #region Constructors protected ObservableKeyedCollection() { dict = new Dictionary(); } protected ObservableKeyedCollection(int capacity) { dict = new Dictionary(capacity); } protected ObservableKeyedCollection(IEqualityComparer comparer) { dict = new Dictionary(comparer); } protected ObservableKeyedCollection(IEnumerable collection) { if (collection == null) throw new ArgumentNullException(); dict = new Dictionary(); foreach (TItem item in collection) dict.Add(GetKeyForItem(item), item); } protected ObservableKeyedCollection(int capacity, IEqualityComparer comparer) { dict = new Dictionary(capacity, comparer); } protected ObservableKeyedCollection(IEnumerable collection, IEqualityComparer comparer) { if (collection == null) throw new ArgumentNullException(); dict = new Dictionary(comparer); foreach (TItem item in collection) dict.Add(GetKeyForItem(item), item); } [StorableConstructor] protected ObservableKeyedCollection(StorableConstructorFlag deserializing) { } #endregion protected abstract TKey GetKeyForItem(TItem item); protected void UpdateItemKey(TItem item) { if (item == null) throw new ArgumentNullException(); TKey oldKey = default(TKey); bool oldKeyFound = false; foreach (KeyValuePair entry in dict) { if (entry.Value.Equals(item)) { oldKey = entry.Key; oldKeyFound = true; break; } } if (!oldKeyFound) throw new ArgumentException("Item not found"); dict.Remove(oldKey); dict.Add(GetKeyForItem(item), item); OnPropertyChanged("Item[]"); OnItemsReplaced(new TItem[] { item }, new TItem[] { item }); } #region Access public bool ContainsKey(TKey key) { return dict.ContainsKey(key); } public bool Contains(TItem item) { return dict.ContainsValue(item); } public bool TryGetValue(TKey key, out TItem item) { return dict.TryGetValue(key, out item); } public bool Exists(Predicate match) { if (match == null) throw new ArgumentNullException(); foreach (TItem item in dict.Values) { if (match(item)) return true; } return false; } public TItem Find(Predicate match) { if (match == null) throw new ArgumentNullException(); foreach (TItem item in dict.Values) { if (match(item)) return item; } return default(TItem); } public ICollection FindAll(Predicate match) { if (match == null) throw new ArgumentNullException(); List result = new List(); foreach (TItem item in dict.Values) { if (match(item)) result.Add(item); } return result; } #endregion #region Manipulation public void Add(TItem item) { dict.Add(GetKeyForItem(item), item); OnPropertyChanged("Item[]"); OnPropertyChanged("Count"); OnItemsAdded(new TItem[] { item }); } public void AddRange(IEnumerable collection) { if (collection == null) throw new ArgumentNullException(); bool empty = true; foreach (TItem item in collection) { dict.Add(GetKeyForItem(item), item); empty = false; } if (!empty) { OnPropertyChanged("Item[]"); OnPropertyChanged("Count"); OnItemsAdded(collection); } } public bool Remove(TKey key) { TItem item; if (TryGetValue(key, out item)) { dict.Remove(key); OnPropertyChanged("Item[]"); OnPropertyChanged("Count"); OnItemsRemoved(new TItem[] { item }); return true; } return false; } public bool Remove(TItem item) { if (dict.Remove(GetKeyForItem(item))) { OnPropertyChanged("Item[]"); OnPropertyChanged("Count"); OnItemsRemoved(new TItem[] { item }); return true; } return false; } public void RemoveRange(IEnumerable collection) { if (collection == null) throw new ArgumentNullException(); List items = new List(); foreach (TItem item in collection) { if (dict.Remove(GetKeyForItem(item))) items.Add(item); } if (items.Count > 0) { OnPropertyChanged("Item[]"); OnPropertyChanged("Count"); OnItemsRemoved(items); } } public int RemoveAll(Predicate match) { ICollection items = FindAll(match); RemoveRange(items); return items.Count; } public void Clear() { if (dict.Count > 0) { TItem[] items = dict.Values.ToArray(); dict.Clear(); OnPropertyChanged("Item[]"); OnPropertyChanged("Count"); OnCollectionReset(new TItem[0], items); } } #endregion #region Conversion public ReadOnlyObservableKeyedCollection AsReadOnly() { return new ReadOnlyObservableKeyedCollection(this); } public TItem[] ToArray() { return dict.Values.ToArray(); } public void CopyTo(TItem[] array, int arrayIndex) { dict.Values.CopyTo(array, arrayIndex); } public ICollection ConvertAll(Converter converter) { if (converter == null) throw new ArgumentNullException(); List result = new List(); foreach (TItem item in dict.Values) result.Add(converter(item)); return result; } #endregion #region Processing public void ForEach(Action action) { if (action == null) throw new ArgumentNullException(); foreach (TItem item in dict.Values) action(item); } public bool TrueForAll(Predicate match) { if (match == null) throw new ArgumentNullException(); foreach (TItem item in dict.Values) if (!match(item)) return false; return true; } #endregion #region Enumeration public IEnumerator GetEnumerator() { return dict.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return dict.Values.GetEnumerator(); } #endregion #region Events [field: NonSerialized] public event CollectionItemsChangedEventHandler ItemsAdded; protected virtual void OnItemsAdded(IEnumerable items) { CollectionItemsChangedEventHandler handler = ItemsAdded; if (handler != null) handler(this, new CollectionItemsChangedEventArgs(items)); } [field: NonSerialized] public event CollectionItemsChangedEventHandler ItemsRemoved; protected virtual void OnItemsRemoved(IEnumerable items) { CollectionItemsChangedEventHandler handler = ItemsRemoved; if (handler != null) handler(this, new CollectionItemsChangedEventArgs(items)); } [field: NonSerialized] public event CollectionItemsChangedEventHandler ItemsReplaced; protected virtual void OnItemsReplaced(IEnumerable items, IEnumerable oldItems) { CollectionItemsChangedEventHandler handler = ItemsReplaced; if (handler != null) handler(this, new CollectionItemsChangedEventArgs(items, oldItems)); } [field: NonSerialized] public event CollectionItemsChangedEventHandler CollectionReset; protected virtual void OnCollectionReset(IEnumerable items, IEnumerable oldItems) { CollectionItemsChangedEventHandler handler = CollectionReset; if (handler != null) handler(this, new CollectionItemsChangedEventArgs(items, oldItems)); } [field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } #endregion } }