Free cookie consent management tool by TermsFeed Policy Generator

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

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

Implemented ReadOnlyView property for items (#969).

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