svn path=/trunk/mcs/; revision=104772
[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 #if NET_2_0
24
25 using System;
26 using System.Collections;
27 using System.Collections.Generic;
28 using System.Collections.ObjectModel;
29 using System.Reflection;
30
31 namespace System.ComponentModel {
32         [SerializableAttribute] 
33         public class BindingList<T> : Collection<T>,
34                 IBindingList, IList, ICollection, 
35                 IEnumerable, ICancelAddNew, IRaiseItemChangedEvents
36         {
37                 bool allow_edit = true;
38                 bool allow_remove = true;
39                 bool allow_new;
40                 bool allow_new_set;
41
42                 bool raise_list_changed_events = true;
43                 
44                 bool type_has_default_ctor;
45                 bool type_raises_item_changed_events;
46
47                 bool add_pending;
48                 int pending_add_index;
49
50                 void CheckType ()
51                 {
52                         ConstructorInfo ci = typeof (T).GetConstructor (Type.EmptyTypes);
53                         type_has_default_ctor = (ci != null);
54                         type_raises_item_changed_events = typeof (INotifyPropertyChanged).IsAssignableFrom (typeof (T));
55                 }
56
57                 public BindingList (IList<T> list) : base(list)
58                 {
59                         CheckType ();
60                 }
61
62                 public BindingList () : base ()
63                 {
64                         CheckType ();
65                 }
66
67                 public bool AllowEdit {
68                         get { return allow_edit; }
69                         set {
70                                 if (allow_edit != value) {
71                                         allow_edit = value;
72
73                                         if (raise_list_changed_events)
74                                                 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
75                                 }
76                         }
77                 }
78
79                 public bool AllowNew {
80                         get {
81                                 /* if the user explicitly it, return that value */
82                                 if (allow_new_set)
83                                         return allow_new;
84
85                                 /* if the list type has a default constructor we allow new */
86                                 if (type_has_default_ctor)
87                                         return true;
88
89                                 /* if the user adds a delegate, we return true even if
90                                    the type doesn't have a default ctor */
91                                 if (AddingNew != null)
92                                         return true;
93
94                                 return false;
95                         }
96                         set {
97                                 // this funky check (using AllowNew
98                                 // instead of allow_new allows us to
99                                 // keep the logic for the 3 cases in
100                                 // one place (the getter) instead of
101                                 // spreading them around the file (in
102                                 // the ctor, in the AddingNew add
103                                 // handler, etc.
104                                 if (AllowNew != value) {
105                                         allow_new_set = true;
106
107                                         allow_new = value;
108
109                                         if (raise_list_changed_events)
110                                                 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
111                                 }
112                         }
113                 }
114
115                 public bool AllowRemove {
116                         get { return allow_remove; }
117                         set {
118                                 if (allow_remove != value) {
119                                         allow_remove = value;
120
121                                         if (raise_list_changed_events)
122                                                 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
123                                 }
124                         }
125                 }
126
127                 protected virtual bool IsSortedCore {
128                         get { return false; }
129                 }
130
131                 public bool RaiseListChangedEvents {
132                         get { return raise_list_changed_events; }
133                         set { raise_list_changed_events = value; }
134                 }
135
136                 protected virtual ListSortDirection SortDirectionCore {
137                         get { return ListSortDirection.Ascending; }
138                 }
139
140                 protected virtual PropertyDescriptor SortPropertyCore {
141                         get { return null; }
142                 }
143
144                 protected virtual bool SupportsChangeNotificationCore {
145                         get { return true; }
146                 }
147
148                 protected virtual bool SupportsSearchingCore {
149                         get { return false; }
150                 }
151
152                 protected virtual bool SupportsSortingCore {
153                         get { return false; }
154                 }
155
156                 public event AddingNewEventHandler AddingNew;
157                 public event ListChangedEventHandler ListChanged;
158
159                 public T AddNew ()
160                 {
161                         return (T)AddNewCore ();
162                 }
163
164                 protected virtual object AddNewCore ()
165                 {
166                         if (!AllowNew)
167                                 throw new InvalidOperationException ();
168
169                         AddingNewEventArgs args = new AddingNewEventArgs ();
170
171                         OnAddingNew (args);
172
173                         T new_obj = (T)args.NewObject;
174                         if (new_obj == null) {
175                                 if (!type_has_default_ctor)
176                                         throw new InvalidOperationException ();
177
178                                 new_obj = (T)Activator.CreateInstance (typeof (T));
179                         }
180
181                         Add (new_obj);
182                         pending_add_index = IndexOf (new_obj);
183                         add_pending = true;
184
185                         if (raise_list_changed_events)
186                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, pending_add_index));
187                         
188                         return new_obj;
189                 }
190
191                 protected virtual void ApplySortCore (PropertyDescriptor prop, ListSortDirection direction)
192                 {
193                         throw new NotSupportedException ();
194                 }
195
196                 public virtual void CancelNew (int itemIndex)
197                 {
198                         if (!add_pending)
199                                 return;
200
201                         if (itemIndex != pending_add_index)
202                                 return;
203
204                         add_pending = false;
205
206                         base.RemoveItem (itemIndex);
207
208                         if (raise_list_changed_events)
209                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, itemIndex));
210                 }
211
212                 protected override void ClearItems ()
213                 {
214                         EndNew (pending_add_index);
215
216                         base.ClearItems ();
217
218                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
219                 }
220
221                 public virtual void EndNew (int itemIndex)
222                 {
223                         if (!add_pending)
224                                 return;
225
226                         if (itemIndex != pending_add_index)
227                                 return;
228
229                         add_pending = false;
230                 }
231
232                 protected virtual int FindCore (PropertyDescriptor prop, object key)
233                 {
234                         throw new NotSupportedException ();
235                 }
236
237                 protected override void InsertItem (int index, T item)
238                 {
239                         EndNew (pending_add_index);
240
241                         base.InsertItem (index, item);
242
243                         if (raise_list_changed_events)
244                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, index));
245                 }
246
247                 protected virtual void OnAddingNew (AddingNewEventArgs e)
248                 {
249                         if (AddingNew != null)
250                                 AddingNew (this, e);
251                 }
252
253                 protected virtual void OnListChanged (ListChangedEventArgs e)
254                 {
255                         if (ListChanged != null)
256                                 ListChanged (this, e);
257                 }
258
259                 protected override void RemoveItem (int index)
260                 {
261                         if (!AllowRemove)
262                                 throw new NotSupportedException ();
263
264                         EndNew (pending_add_index);
265
266                         base.RemoveItem (index);
267
268                         if (raise_list_changed_events)
269                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
270                 }
271
272                 protected virtual void RemoveSortCore ()
273                 {
274                         throw new NotSupportedException ();
275                 }
276
277                 public void ResetBindings ()
278                 {
279                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
280                 }
281
282                 public void ResetItem (int position)
283                 {
284                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, position));
285                 }
286
287                 protected override void SetItem (int index, T item)
288                 {
289                         base.SetItem (index, item);
290
291                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, index));
292                 }
293
294                 void IBindingList.AddIndex (PropertyDescriptor index)
295                 {
296                         /* no implementation by default */
297                 }
298
299                 object IBindingList.AddNew ()
300                 {
301                         return AddNew ();
302                 }
303
304                 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
305                 {
306                         ApplySortCore (property, direction);
307                 }
308
309                 int IBindingList.Find (PropertyDescriptor property, object key)
310                 {
311                         return FindCore (property, key);
312                 }
313
314                 void IBindingList.RemoveIndex (PropertyDescriptor property)
315                 {
316                         /* no implementation by default */
317                 }
318
319                 void IBindingList.RemoveSort ()
320                 {
321                         RemoveSortCore ();
322                 }
323
324                 bool IBindingList.IsSorted {
325                         get { return IsSortedCore; }
326                 }
327
328                 ListSortDirection IBindingList.SortDirection {
329                         get { return SortDirectionCore; }
330                 }
331
332                 PropertyDescriptor IBindingList.SortProperty {
333                         get { return SortPropertyCore; }
334                 }
335
336                 bool IBindingList.AllowEdit {
337                         get { return AllowEdit; }
338                 }
339
340                 bool IBindingList.AllowNew {
341                         get { return AllowNew; }
342                 }
343
344                 bool IBindingList.AllowRemove {
345                         get { return AllowRemove; }
346                 }
347
348                 bool IBindingList.SupportsChangeNotification {
349                         get { return SupportsChangeNotificationCore; }
350                 }
351
352                 bool IBindingList.SupportsSearching {
353                         get { return SupportsSearchingCore; }
354                 }
355
356                 bool IBindingList.SupportsSorting {
357                         get { return SupportsSortingCore; }
358                 }
359
360                 bool IRaiseItemChangedEvents.RaisesItemChangedEvents {
361                         get { return type_raises_item_changed_events; }
362                 }
363         }
364
365 }
366
367 #endif