Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Collections/3.3/ObservableList.cs @ 3016

Last change on this file since 3016 was 2994, checked in by epitzer, 15 years ago

Make StorableClass attribute compulsory for StorableSerializer to work, add named property StorableClassType to choose between Empty and MarkedOnly, later other options will be added. (#548)

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