Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / System / System.ComponentModel / BindingList.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2007 Novell, Inc.
21 //
22
23 using System;
24 using System.Collections;
25 using System.Collections.Generic;
26 using System.Collections.ObjectModel;
27 using System.Reflection;
28
29 namespace System.ComponentModel {
30         [SerializableAttribute] 
31         public class BindingList<T> : Collection<T>,
32                 IBindingList, IList, ICollection, 
33                 IEnumerable, ICancelAddNew, IRaiseItemChangedEvents
34         {
35                 bool allow_edit = true;
36                 bool allow_remove = true;
37                 bool allow_new;
38                 bool allow_new_set;
39
40                 bool raise_list_changed_events = true;
41                 
42                 bool type_has_default_ctor;
43                 bool type_raises_item_changed_events;
44
45                 bool add_pending;
46                 int pending_add_index;
47
48                 void CheckType ()
49                 {
50                         ConstructorInfo ci = typeof (T).GetConstructor (Type.EmptyTypes);
51                         type_has_default_ctor = (ci != null);
52                         type_raises_item_changed_events = typeof (INotifyPropertyChanged).IsAssignableFrom (typeof (T));
53                 }
54
55                 public BindingList (IList<T> list) : base(list)
56                 {
57                         CheckType ();
58                 }
59
60                 public BindingList () : base ()
61                 {
62                         CheckType ();
63                 }
64
65                 public bool AllowEdit {
66                         get { return allow_edit; }
67                         set {
68                                 if (allow_edit != value) {
69                                         allow_edit = value;
70
71                                         if (raise_list_changed_events)
72                                                 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
73                                 }
74                         }
75                 }
76
77                 public bool AllowNew {
78                         get {
79                                 /* if the user explicitly it, return that value */
80                                 if (allow_new_set)
81                                         return allow_new;
82
83                                 /* if the list type has a default constructor we allow new */
84                                 if (type_has_default_ctor)
85                                         return true;
86
87                                 /* if the user adds a delegate, we return true even if
88                                    the type doesn't have a default ctor */
89                                 if (AddingNew != null)
90                                         return true;
91
92                                 return false;
93                         }
94                         set {
95                                 // this funky check (using AllowNew
96                                 // instead of allow_new allows us to
97                                 // keep the logic for the 3 cases in
98                                 // one place (the getter) instead of
99                                 // spreading them around the file (in
100                                 // the ctor, in the AddingNew add
101                                 // handler, etc.
102                                 if (AllowNew != value) {
103                                         allow_new_set = true;
104
105                                         allow_new = value;
106
107                                         if (raise_list_changed_events)
108                                                 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
109                                 }
110                         }
111                 }
112
113                 public bool AllowRemove {
114                         get { return allow_remove; }
115                         set {
116                                 if (allow_remove != value) {
117                                         allow_remove = value;
118
119                                         if (raise_list_changed_events)
120                                                 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
121                                 }
122                         }
123                 }
124
125                 protected virtual bool IsSortedCore {
126                         get { return false; }
127                 }
128
129                 public bool RaiseListChangedEvents {
130                         get { return raise_list_changed_events; }
131                         set { raise_list_changed_events = value; }
132                 }
133
134                 protected virtual ListSortDirection SortDirectionCore {
135                         get { return ListSortDirection.Ascending; }
136                 }
137
138                 protected virtual PropertyDescriptor SortPropertyCore {
139                         get { return null; }
140                 }
141
142                 protected virtual bool SupportsChangeNotificationCore {
143                         get { return true; }
144                 }
145
146                 protected virtual bool SupportsSearchingCore {
147                         get { return false; }
148                 }
149
150                 protected virtual bool SupportsSortingCore {
151                         get { return false; }
152                 }
153
154                 public event AddingNewEventHandler AddingNew;
155                 public event ListChangedEventHandler ListChanged;
156
157                 public T AddNew ()
158                 {
159                         return (T)AddNewCore ();
160                 }
161
162                 protected virtual object AddNewCore ()
163                 {
164                         if (!AllowNew)
165                                 throw new InvalidOperationException ();
166
167                         AddingNewEventArgs args = new AddingNewEventArgs ();
168
169                         OnAddingNew (args);
170
171                         T new_obj = (T)args.NewObject;
172                         if (new_obj == null) {
173                                 if (!type_has_default_ctor)
174                                         throw new InvalidOperationException ();
175
176                                 new_obj = (T)Activator.CreateInstance (typeof (T));
177                         }
178
179                         Add (new_obj);
180                         pending_add_index = IndexOf (new_obj);
181                         add_pending = true;
182                         
183                         return new_obj;
184                 }
185
186                 protected virtual void ApplySortCore (PropertyDescriptor prop, ListSortDirection direction)
187                 {
188                         throw new NotSupportedException ();
189                 }
190
191                 public virtual void CancelNew (int itemIndex)
192                 {
193                         if (!add_pending)
194                                 return;
195
196                         if (itemIndex != pending_add_index)
197                                 return;
198
199                         add_pending = false;
200
201                         base.RemoveItem (itemIndex);
202
203                         if (raise_list_changed_events)
204                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, itemIndex));
205                 }
206
207                 protected override void ClearItems ()
208                 {
209                         EndNew (pending_add_index);
210                         if (type_raises_item_changed_events) {
211                                 foreach ( T item in base.Items ) {
212                                         (item as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
213                                 }
214                         }
215                         base.ClearItems ();
216
217                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
218                 }
219
220                 public virtual void EndNew (int itemIndex)
221                 {
222                         if (!add_pending)
223                                 return;
224
225                         if (itemIndex != pending_add_index)
226                                 return;
227
228                         add_pending = false;
229                 }
230
231                 protected virtual int FindCore (PropertyDescriptor prop, object key)
232                 {
233                         throw new NotSupportedException ();
234                 }
235
236                 protected override void InsertItem (int index, T item)
237                 {
238                         EndNew (pending_add_index);
239
240                         base.InsertItem (index, item);
241
242                         if (raise_list_changed_events)
243                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, index));
244
245                         if (item != null && type_raises_item_changed_events)
246                                 (item as INotifyPropertyChanged).PropertyChanged += Item_PropertyChanged;
247                 }
248
249                 void Item_PropertyChanged (object item, PropertyChangedEventArgs args)
250                 {
251                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, base.IndexOf ((T) item)) );
252                 }
253
254                 protected virtual void OnAddingNew (AddingNewEventArgs e)
255                 {
256                         if (AddingNew != null)
257                                 AddingNew (this, e);
258                 }
259
260                 protected virtual void OnListChanged (ListChangedEventArgs e)
261                 {
262                         if (ListChanged != null)
263                                 ListChanged (this, e);
264                 }
265
266                 protected override void RemoveItem (int index)
267                 {
268                         if (!AllowRemove)
269                                 throw new NotSupportedException ();
270
271                         EndNew (pending_add_index);
272                         if (type_raises_item_changed_events) {
273                                 (base[index] as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
274                         }
275                         base.RemoveItem (index);
276
277                         if (raise_list_changed_events)
278                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
279                 }
280
281                 protected virtual void RemoveSortCore ()
282                 {
283                         throw new NotSupportedException ();
284                 }
285
286                 public void ResetBindings ()
287                 {
288                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
289                 }
290
291                 public void ResetItem (int position)
292                 {
293                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, position));
294                 }
295
296                 protected override void SetItem (int index, T item)
297                 {
298                         if (type_raises_item_changed_events) {
299                                 (base[index] as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
300                                 (item as INotifyPropertyChanged).PropertyChanged += Item_PropertyChanged;
301                         }
302                         base.SetItem (index, item);
303
304                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, index));
305                 }
306
307                 void IBindingList.AddIndex (PropertyDescriptor index)
308                 {
309                         /* no implementation by default */
310                 }
311
312                 object IBindingList.AddNew ()
313                 {
314                         return AddNew ();
315                 }
316
317                 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
318                 {
319                         ApplySortCore (property, direction);
320                 }
321
322                 int IBindingList.Find (PropertyDescriptor property, object key)
323                 {
324                         return FindCore (property, key);
325                 }
326
327                 void IBindingList.RemoveIndex (PropertyDescriptor property)
328                 {
329                         /* no implementation by default */
330                 }
331
332                 void IBindingList.RemoveSort ()
333                 {
334                         RemoveSortCore ();
335                 }
336
337                 bool IBindingList.IsSorted {
338                         get { return IsSortedCore; }
339                 }
340
341                 ListSortDirection IBindingList.SortDirection {
342                         get { return SortDirectionCore; }
343                 }
344
345                 PropertyDescriptor IBindingList.SortProperty {
346                         get { return SortPropertyCore; }
347                 }
348
349                 bool IBindingList.AllowEdit {
350                         get { return AllowEdit; }
351                 }
352
353                 bool IBindingList.AllowNew {
354                         get { return AllowNew; }
355                 }
356
357                 bool IBindingList.AllowRemove {
358                         get { return AllowRemove; }
359                 }
360
361                 bool IBindingList.SupportsChangeNotification {
362                         get { return SupportsChangeNotificationCore; }
363                 }
364
365                 bool IBindingList.SupportsSearching {
366                         get { return SupportsSearchingCore; }
367                 }
368
369                 bool IBindingList.SupportsSorting {
370                         get { return SupportsSortingCore; }
371                 }
372
373                 bool IRaiseItemChangedEvents.RaisesItemChangedEvents {
374                         get { return type_raises_item_changed_events; }
375                 }
376         }
377
378 }
379