Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Collections/3.3/ObservableKeyedCollection.cs @ 2664

Last change on this file since 2664 was 2664, checked in by swagner, 14 years ago

Abandoned policy that the names of all abstract base classes have to end in "Base" (#95)

File size: 9.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections;
24using System.Collections.Generic;
25using System.Collections.ObjectModel;
26using System.ComponentModel;
27using System.Linq;
28using System.Text;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30
31namespace HeuristicLab.Collections {
32  [Serializable]
33  public abstract class ObservableKeyedCollection<TKey, TItem> : IObservableKeyedCollection<TKey, TItem> {
34    [Storable]
35    private Dictionary<TKey, TItem> dict;
36
37    #region Properties
38    public int Count {
39      get { return dict.Count; }
40    }
41    public IEqualityComparer<TKey> Comparer {
42      get { return dict.Comparer; }
43    }
44    bool ICollection<TItem>.IsReadOnly {
45      get { return ((ICollection<KeyValuePair<TKey, TItem>>)dict).IsReadOnly; }
46    }
47
48    public TItem this[TKey key] {
49      get {
50        return dict[key];
51      }
52    }
53    #endregion
54
55    #region Constructors
56    protected ObservableKeyedCollection() {
57      dict = new Dictionary<TKey, TItem>();
58    }
59    protected ObservableKeyedCollection(int capacity) {
60      dict = new Dictionary<TKey, TItem>(capacity);
61    }
62    protected ObservableKeyedCollection(IEqualityComparer<TKey> comparer) {
63      dict = new Dictionary<TKey, TItem>(comparer);
64    }
65    protected ObservableKeyedCollection(IEnumerable<TItem> collection) {
66      if (collection == null) throw new ArgumentNullException();
67      dict = new Dictionary<TKey, TItem>();
68      foreach (TItem item in collection)
69        dict.Add(GetKeyForItem(item), item);
70      OnItemsAdded(collection);
71    }
72    protected ObservableKeyedCollection(int capacity, IEqualityComparer<TKey> comparer) {
73      dict = new Dictionary<TKey, TItem>(capacity, comparer);
74    }
75    protected ObservableKeyedCollection(IEnumerable<TItem> collection, IEqualityComparer<TKey> comparer) {
76      if (collection == null) throw new ArgumentNullException();
77      dict = new Dictionary<TKey, TItem>(comparer);
78      foreach (TItem item in collection)
79        dict.Add(GetKeyForItem(item), item);
80      OnItemsAdded(collection);
81    }
82    #endregion
83
84    protected abstract TKey GetKeyForItem(TItem item);
85    protected void UpdateItemKey(TItem item) {
86      if (item == null) throw new ArgumentNullException();
87      TKey oldKey = default(TKey);
88      bool oldKeyFound = false;
89      foreach (KeyValuePair<TKey, TItem> entry in dict) {
90        if (entry.Value.Equals(item)) {
91          oldKey = entry.Key;
92          oldKeyFound = true;
93          break;
94        }
95      }
96      if (!oldKeyFound) throw new ArgumentException("Item not found");
97      dict.Remove(oldKey);
98      dict.Add(GetKeyForItem(item), item);
99      OnPropertyChanged("Item[]");
100      OnItemsReplaced(new TItem[] { item }, new TItem[] { item });
101    }
102
103    #region Access
104    public bool ContainsKey(TKey key) {
105      return dict.ContainsKey(key);
106    }
107    public bool Contains(TItem item) {
108      return dict.ContainsValue(item);
109    }
110
111    public bool TryGetValue(TKey key, out TItem item) {
112      return dict.TryGetValue(key, out item);
113    }
114
115    public bool Exists(Predicate<TItem> match) {
116      if (match == null) throw new ArgumentNullException();
117      foreach (TItem item in dict.Values) {
118        if (match(item)) return true;
119      }
120      return false;
121    }
122
123    public TItem Find(Predicate<TItem> match) {
124      if (match == null) throw new ArgumentNullException();
125      foreach (TItem item in dict.Values) {
126        if (match(item)) return item;
127      }
128      return default(TItem);
129    }
130    public ICollection<TItem> FindAll(Predicate<TItem> match) {
131      if (match == null) throw new ArgumentNullException();
132      List<TItem> result = new List<TItem>();
133      foreach (TItem item in dict.Values) {
134        if (match(item)) result.Add(item);
135      }
136      return result;
137    }
138    #endregion
139
140    #region Manipulation
141    public void Add(TItem item) {
142      dict.Add(GetKeyForItem(item), item);
143      OnPropertyChanged("Item[]");
144      OnPropertyChanged("Count");
145      OnItemsAdded(new TItem[] { item });
146    }
147    public void AddRange(IEnumerable<TItem> collection) {
148      if (collection == null) throw new ArgumentNullException();
149      bool empty = true;
150      foreach (TItem item in collection) {
151        dict.Add(GetKeyForItem(item), item);
152        empty = false;
153      }
154      if (!empty) {
155        OnPropertyChanged("Item[]");
156        OnPropertyChanged("Count");
157        OnItemsAdded(collection);
158      }
159    }
160
161    public bool Remove(TKey key) {
162      TItem item;
163      if (TryGetValue(key, out item)) {
164        dict.Remove(key);
165        OnPropertyChanged("Item[]");
166        OnPropertyChanged("Count");
167        OnItemsRemoved(new TItem[] { item });
168        return true;
169      }
170      return false;
171    }
172    public bool Remove(TItem item) {
173      if (dict.Remove(GetKeyForItem(item))) {
174        OnPropertyChanged("Item[]");
175        OnPropertyChanged("Count");
176        OnItemsRemoved(new TItem[] { item });
177        return true;
178      }
179      return false;
180    }
181    public void RemoveRange(IEnumerable<TItem> collection) {
182      if (collection == null) throw new ArgumentNullException();
183      List<TItem> items = new List<TItem>();
184      foreach (TItem item in collection) {
185        if (dict.Remove(GetKeyForItem(item)))
186          items.Add(item);
187      }
188      if (items.Count > 0) {
189        OnPropertyChanged("Item[]");
190        OnPropertyChanged("Count");
191        OnItemsRemoved(items);
192      }
193    }
194    public int RemoveAll(Predicate<TItem> match) {
195      ICollection<TItem> items = FindAll(match);
196      RemoveRange(items);
197      return items.Count;
198    }
199
200    public void Clear() {
201      if (dict.Count > 0) {
202        TItem[] items = dict.Values.ToArray();
203        dict.Clear();
204        OnPropertyChanged("Item[]");
205        OnPropertyChanged("Count");
206        OnCollectionReset(new TItem[0], items);
207      }
208    }
209    #endregion
210
211    #region Conversion
212    public ReadOnlyObservableKeyedCollection<TKey, TItem> AsReadOnly() {
213      return new ReadOnlyObservableKeyedCollection<TKey, TItem>(this);
214    }
215    public TItem[] ToArray() {
216      return dict.Values.ToArray();
217    }
218    public void CopyTo(TItem[] array, int arrayIndex) {
219      dict.Values.CopyTo(array, arrayIndex);
220    }
221    public ICollection<TOutput> ConvertAll<TOutput>(Converter<TItem, TOutput> converter) {
222      if (converter == null) throw new ArgumentNullException();
223      List<TOutput> result = new List<TOutput>();
224      foreach (TItem item in dict.Values)
225        result.Add(converter(item));
226      return result;
227    }
228    #endregion
229
230    #region Processing
231    public void ForEach(Action<TItem> action) {
232      if (action == null) throw new ArgumentNullException();
233      foreach (TItem item in dict.Values)
234        action(item);
235    }
236    public bool TrueForAll(Predicate<TItem> match) {
237      if (match == null) throw new ArgumentNullException();
238      foreach (TItem item in dict.Values)
239        if (! match(item)) return false;
240      return true;
241    }
242    #endregion
243
244    #region Enumeration
245    public IEnumerator<TItem> GetEnumerator() {
246      return dict.Values.GetEnumerator();
247    }
248    IEnumerator IEnumerable.GetEnumerator() {
249      return dict.Values.GetEnumerator();
250    }
251    #endregion
252
253    #region Events
254    [field: NonSerialized]
255    public event CollectionItemsChangedEventHandler<TItem> ItemsAdded;
256    protected virtual void OnItemsAdded(IEnumerable<TItem> items) {
257      if (ItemsAdded != null)
258        ItemsAdded(this, new CollectionItemsChangedEventArgs<TItem>(items));
259    }
260
261    [field: NonSerialized]
262    public event CollectionItemsChangedEventHandler<TItem> ItemsRemoved;
263    protected virtual void OnItemsRemoved(IEnumerable<TItem> items) {
264      if (ItemsRemoved != null)
265        ItemsRemoved(this, new CollectionItemsChangedEventArgs<TItem>(items));
266    }
267
268    [field: NonSerialized]
269    public event CollectionItemsChangedEventHandler<TItem> ItemsReplaced;
270    protected virtual void OnItemsReplaced(IEnumerable<TItem> items, IEnumerable<TItem> oldItems) {
271      if (ItemsReplaced != null)
272        ItemsReplaced(this, new CollectionItemsChangedEventArgs<TItem>(items, oldItems));
273    }
274
275    [field: NonSerialized]
276    public event CollectionItemsChangedEventHandler<TItem> CollectionReset;
277    protected virtual void OnCollectionReset(IEnumerable<TItem> items, IEnumerable<TItem> oldItems) {
278      if (CollectionReset != null)
279        CollectionReset(this, new CollectionItemsChangedEventArgs<TItem>(items, oldItems));
280    }
281
282    [field: NonSerialized]
283    public event PropertyChangedEventHandler PropertyChanged;
284    protected virtual void OnPropertyChanged(string propertyName) {
285      if (PropertyChanged != null)
286        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
287    }
288    #endregion
289  }
290}
Note: See TracBrowser for help on using the repository browser.