Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceSpeedUp/HeuristicLab.Collections/3.3/ObservableList.cs @ 14113

Last change on this file since 14113 was 6760, checked in by epitzer, 13 years ago

#1530 integrate changes from trunk

File size: 17.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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.ComponentModel;
26using System.Linq;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Collections {
30  [StorableClass]
31  [Serializable]
32  public class ObservableList<T> : IObservableList<T> {
33    [Storable]
34    protected List<T> list;
35
36    #region Properties
37    public int Capacity {
38      get { return list.Capacity; }
39      set {
40        if (list.Capacity != value) {
41          list.Capacity = value;
42          OnPropertyChanged("Capacity");
43        }
44      }
45    }
46    public int Count {
47      get { return list.Count; }
48    }
49    bool ICollection<T>.IsReadOnly {
50      get { return ((ICollection<T>)list).IsReadOnly; }
51    }
52
53    public T this[int index] {
54      get {
55        return list[index];
56      }
57      set {
58        T item = list[index];
59        if (!((item == null) && (value == null)) && ((item == null) || (!item.Equals(value)))) {
60          list[index] = value;
61          OnItemsReplaced(new IndexedItem<T>[] { new IndexedItem<T>(index, value) }, new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
62          OnPropertyChanged("Item[]");
63        }
64      }
65    }
66    #endregion
67
68    #region Constructors
69    public ObservableList() {
70      list = new List<T>();
71    }
72    public ObservableList(int capacity) {
73      list = new List<T>(capacity);
74    }
75    public ObservableList(IEnumerable<T> collection) {
76      list = new List<T>(collection);
77    }
78    [StorableConstructor]
79    protected ObservableList(bool deserializing) { }
80    #endregion
81
82    #region Access
83    public List<T> GetRange(int index, int count) {
84      return list.GetRange(index, count);
85    }
86
87    public bool Contains(T item) {
88      return list.Contains(item);
89    }
90
91    public int IndexOf(T item) {
92      return list.IndexOf(item);
93    }
94    public int IndexOf(T item, int index) {
95      return list.IndexOf(item, index);
96    }
97    public int IndexOf(T item, int index, int count) {
98      return list.IndexOf(item, index, count);
99    }
100
101    public int LastIndexOf(T item) {
102      return list.LastIndexOf(item);
103    }
104    public int LastIndexOf(T item, int index) {
105      return list.LastIndexOf(item, index);
106    }
107    public int LastIndexOf(T item, int index, int count) {
108      return list.LastIndexOf(item, index, count);
109    }
110
111    public int BinarySearch(T item) {
112      return list.BinarySearch(item);
113    }
114    public int BinarySearch(T item, IComparer<T> comparer) {
115      return list.BinarySearch(item, comparer);
116    }
117    public int BinarySearch(int index, int count, T item, IComparer<T> comparer) {
118      return list.BinarySearch(index, count, item, comparer);
119    }
120
121    public bool Exists(Predicate<T> match) {
122      return list.Exists(match);
123    }
124
125    public T Find(Predicate<T> match) {
126      return list.Find(match);
127    }
128    public List<T> FindAll(Predicate<T> match) {
129      return list.FindAll(match);
130    }
131    public T FindLast(Predicate<T> match) {
132      return list.FindLast(match);
133    }
134
135    public int FindIndex(Predicate<T> match) {
136      return list.FindIndex(match);
137    }
138    public int FindIndex(int startIndex, Predicate<T> match) {
139      return list.FindIndex(startIndex, match);
140    }
141    public int FindIndex(int startIndex, int count, Predicate<T> match) {
142      return list.FindIndex(startIndex, count, match);
143    }
144
145    public int FindLastIndex(Predicate<T> match) {
146      return list.FindLastIndex(match);
147    }
148    public int FindLastIndex(int startIndex, Predicate<T> match) {
149      return list.FindLastIndex(startIndex, match);
150    }
151    public int FindLastIndex(int startIndex, int count, Predicate<T> match) {
152      return list.FindLastIndex(startIndex, count, match);
153    }
154    #endregion
155
156    #region Manipulation
157    public void Add(T item) {
158      int capacity = list.Capacity;
159      list.Add(item);
160      if (list.Capacity != capacity)
161        OnPropertyChanged("Capacity");
162      OnPropertyChanged("Item[]");
163      OnPropertyChanged("Count");
164      OnItemsAdded(new IndexedItem<T>[] { new IndexedItem<T>(list.Count - 1, item) });
165      OnItemsAdded(new T[] { item });
166    }
167    public void AddRange(IEnumerable<T> collection) {
168      int capacity = list.Capacity;
169      int index = list.Count;
170      list.AddRange(collection);
171      List<IndexedItem<T>> items = new List<IndexedItem<T>>();
172      foreach (T item in collection) {
173        items.Add(new IndexedItem<T>(index, item));
174        index++;
175      }
176      if (items.Count > 0) {
177        if (list.Capacity != capacity)
178          OnPropertyChanged("Capacity");
179        OnPropertyChanged("Item[]");
180        OnPropertyChanged("Count");
181        OnItemsAdded(items);
182        OnItemsAdded(collection);
183      }
184    }
185
186    public void Insert(int index, T item) {
187      int capacity = list.Capacity;
188      list.Insert(index, item);
189      if (list.Capacity != capacity)
190        OnPropertyChanged("Capacity");
191      OnPropertyChanged("Item[]");
192      OnPropertyChanged("Count");
193      OnItemsAdded(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
194      OnItemsAdded(new T[] { item });
195    }
196    public void InsertRange(int index, IEnumerable<T> collection) {
197      int capacity = list.Capacity;
198      list.InsertRange(index, collection);
199      List<IndexedItem<T>> items = new List<IndexedItem<T>>();
200      foreach (T item in collection) {
201        items.Add(new IndexedItem<T>(index, item));
202        index++;
203      }
204      if (items.Count > 0) {
205        if (list.Capacity != capacity)
206          OnPropertyChanged("Capacity");
207        OnPropertyChanged("Item[]");
208        OnPropertyChanged("Count");
209        OnItemsAdded(items);
210        OnItemsAdded(collection);
211      }
212    }
213
214    /// <summary>
215    /// Performs a Clear and an AddRange, but does not fire separate events for those operations
216    /// </summary>
217    /// <param name="collection"></param>
218    public void Replace(IEnumerable<T> collection) {
219      List<IndexedItem<T>> oldItems = null;
220      if (list.Any()) oldItems = list.Select((x, i) => new IndexedItem<T>(i, x)).ToList();
221      else oldItems = new List<IndexedItem<T>>();
222
223      int oldCapacity = list.Capacity;
224      list.Clear();
225      list.AddRange(collection);
226
227      List<IndexedItem<T>> items = null;
228      if (list.Any()) items = list.Select((x, i) => new IndexedItem<T>(i, x)).ToList();
229      else items = new List<IndexedItem<T>>();
230
231      if (oldCapacity != list.Capacity) OnPropertyChanged("Capacity");
232      OnPropertyChanged("Item[]");
233      if (oldItems.Count != items.Count) OnPropertyChanged("Count");
234      OnItemsReplaced(items, oldItems);
235    }
236
237    public bool Remove(T item) {
238      int index = list.IndexOf(item);
239      if (index != -1) {
240        list.RemoveAt(index);
241        OnPropertyChanged("Item[]");
242        OnPropertyChanged("Count");
243        OnItemsRemoved(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
244        OnItemsRemoved(new T[] { item });
245        return true;
246      }
247      return false;
248    }
249    public int RemoveAll(Predicate<T> match) {
250      if (match == null) throw new ArgumentNullException();
251      List<IndexedItem<T>> indexedItems = new List<IndexedItem<T>>();
252      List<T> items = new List<T>();
253      for (int i = 0; i < list.Count; i++) {
254        if (match(list[i])) {
255          indexedItems.Add(new IndexedItem<T>(i, list[i]));
256          items.Add(list[i]);
257        }
258      }
259      int result = 0;
260      if (indexedItems.Count > 0) {
261        result = list.RemoveAll(match);
262        OnPropertyChanged("Item[]");
263        OnPropertyChanged("Count");
264        OnItemsRemoved(indexedItems);
265        OnItemsRemoved(items);
266      }
267      return result;
268    }
269    public void RemoveAt(int index) {
270      T item = list[index];
271      list.RemoveAt(index);
272      OnPropertyChanged("Item[]");
273      OnPropertyChanged("Count");
274      OnItemsRemoved(new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
275      OnItemsRemoved(new T[] { item });
276    }
277    public void RemoveRange(int index, int count) {
278      if (count > 0) {
279        IndexedItem<T>[] indexedItems = GetIndexedItems(index, count);
280        T[] items = new T[count];
281        list.CopyTo(index, items, 0, count);
282        list.RemoveRange(index, count);
283        OnPropertyChanged("Item[]");
284        OnPropertyChanged("Count");
285        OnItemsRemoved(indexedItems);
286        OnItemsRemoved(items);
287      }
288    }
289
290    public void Clear() {
291      if (list.Count > 0) {
292        IndexedItem<T>[] indexedItems = GetIndexedItems();
293        T[] items = list.ToArray();
294        list.Clear();
295        OnPropertyChanged("Item[]");
296        OnPropertyChanged("Count");
297        OnCollectionReset(new IndexedItem<T>[0], indexedItems);
298        OnCollectionReset(new T[0], items);
299      }
300    }
301
302    public void Reverse() {
303      if (list.Count > 1) {
304        IndexedItem<T>[] oldItems = GetIndexedItems();
305        list.Reverse();
306        OnPropertyChanged("Item[]");
307        OnItemsMoved(GetIndexedItems(), oldItems);
308      }
309    }
310    public void Reverse(int index, int count) {
311      if (count > 1) {
312        IndexedItem<T>[] oldItems = GetIndexedItems(index, count);
313        list.Reverse(index, count);
314        OnPropertyChanged("Item[]");
315        OnItemsMoved(GetIndexedItems(index, count), oldItems);
316      }
317    }
318
319    public void Sort() {
320      if (list.Count > 1) {
321        IndexedItem<T>[] oldItems = GetIndexedItems();
322        list.Sort();
323        OnPropertyChanged("Item[]");
324        OnItemsMoved(GetIndexedItems(), oldItems);
325      }
326    }
327    public void Sort(Comparison<T> comparison) {
328      if (list.Count > 1) {
329        IndexedItem<T>[] oldItems = GetIndexedItems();
330        list.Sort(comparison);
331        OnPropertyChanged("Item[]");
332        OnItemsMoved(GetIndexedItems(), oldItems);
333      }
334    }
335    public void Sort(IComparer<T> comparer) {
336      if (list.Count > 1) {
337        IndexedItem<T>[] oldItems = GetIndexedItems();
338        list.Sort(comparer);
339        OnPropertyChanged("Item[]");
340        OnItemsMoved(GetIndexedItems(), oldItems);
341      }
342    }
343    public void Sort(int index, int count, IComparer<T> comparer) {
344      if (count > 1) {
345        IndexedItem<T>[] oldItems = GetIndexedItems(index, count);
346        list.Sort(index, count, comparer);
347        OnPropertyChanged("Item[]");
348        OnItemsMoved(GetIndexedItems(index, count), oldItems);
349      }
350    }
351    #endregion
352
353    #region Conversion
354    public ReadOnlyObservableList<T> AsReadOnly() {
355      return new ReadOnlyObservableList<T>(this);
356    }
357    public T[] ToArray() {
358      return list.ToArray();
359    }
360    public void CopyTo(T[] array) {
361      list.CopyTo(array);
362    }
363    public void CopyTo(T[] array, int arrayIndex) {
364      list.CopyTo(array, arrayIndex);
365    }
366    public void CopyTo(int index, T[] array, int arrayIndex, int count) {
367      list.CopyTo(index, array, arrayIndex, count);
368    }
369    public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter) {
370      return list.ConvertAll<TOutput>(converter);
371    }
372    #endregion
373
374    #region Processing
375    public void ForEach(Action<T> action) {
376      list.ForEach(action);
377    }
378    public bool TrueForAll(Predicate<T> match) {
379      return list.TrueForAll(match);
380    }
381    #endregion
382
383    #region Enumeration
384    public IEnumerator<T> GetEnumerator() {
385      return list.GetEnumerator();
386    }
387    IEnumerator IEnumerable.GetEnumerator() {
388      return list.GetEnumerator();
389    }
390    #endregion
391
392    #region Helpers
393    public void TrimExcess() {
394      int capacity = list.Capacity;
395      list.TrimExcess();
396      if (list.Capacity != capacity)
397        OnPropertyChanged("Capacity");
398    }
399    #endregion
400
401    #region Events
402    [field: NonSerialized]
403    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsAdded;
404    protected virtual void OnItemsAdded(IEnumerable<IndexedItem<T>> items) {
405      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsAdded;
406      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items));
407    }
408
409    [field: NonSerialized]
410    private event CollectionItemsChangedEventHandler<T> itemsAdded;
411    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.ItemsAdded {
412      add { itemsAdded += value; }
413      remove { itemsAdded -= value; }
414    }
415    private void OnItemsAdded(IEnumerable<T> items) {
416      CollectionItemsChangedEventHandler<T> handler = itemsAdded;
417      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items));
418    }
419
420    [field: NonSerialized]
421    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsRemoved;
422    protected virtual void OnItemsRemoved(IEnumerable<IndexedItem<T>> items) {
423      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsRemoved;
424      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items));
425    }
426
427    [field: NonSerialized]
428    private event CollectionItemsChangedEventHandler<T> itemsRemoved;
429    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.ItemsRemoved {
430      add { itemsRemoved += value; }
431      remove { itemsRemoved -= value; }
432    }
433    private void OnItemsRemoved(IEnumerable<T> items) {
434      CollectionItemsChangedEventHandler<T> handler = itemsRemoved;
435      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items));
436    }
437
438    [field: NonSerialized]
439    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsReplaced;
440    protected virtual void OnItemsReplaced(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
441      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsReplaced;
442      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
443    }
444
445    [field: NonSerialized]
446    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsMoved;
447    protected virtual void OnItemsMoved(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
448      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsMoved;
449      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
450    }
451
452    [field: NonSerialized]
453    public event CollectionItemsChangedEventHandler<IndexedItem<T>> CollectionReset;
454    protected virtual void OnCollectionReset(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
455      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = CollectionReset;
456      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
457    }
458
459    [field: NonSerialized]
460    private event CollectionItemsChangedEventHandler<T> collectionReset;
461    event CollectionItemsChangedEventHandler<T> INotifyObservableCollectionItemsChanged<T>.CollectionReset {
462      add { collectionReset += value; }
463      remove { collectionReset -= value; }
464    }
465    private void OnCollectionReset(IEnumerable<T> items, IEnumerable<T> oldItems) {
466      CollectionItemsChangedEventHandler<T> handler = collectionReset;
467      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<T>(items, oldItems));
468    }
469
470    [field: NonSerialized]
471    public event PropertyChangedEventHandler PropertyChanged;
472    protected virtual void OnPropertyChanged(string propertyName) {
473      PropertyChangedEventHandler handler = PropertyChanged;
474      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
475    }
476    #endregion
477
478    #region Private helpers
479    private IndexedItem<T>[] GetIndexedItems() {
480      IndexedItem<T>[] items = new IndexedItem<T>[list.Count];
481      for (int i = 0; i < list.Count; i++)
482        items[i] = new IndexedItem<T>(i, list[i]);
483      return items;
484    }
485    private IndexedItem<T>[] GetIndexedItems(int index, int count) {
486      IndexedItem<T>[] items = new IndexedItem<T>[count];
487      for (int i = 0; i < count; i++)
488        items[i] = new IndexedItem<T>(index + i, list[index + i]);
489      return items;
490    }
491    #endregion
492  }
493}
Note: See TracBrowser for help on using the repository browser.