Implement MachineKey.Protect and MachineKey.Unprotect
[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                         var property_info = item.GetType ().GetProperty (args.PropertyName);
252
253                         if (property_info != null) {
254                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, base.IndexOf ((T) item),
255                                                         new ReflectionPropertyDescriptor (property_info)) );
256                         } else {
257                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, base.IndexOf ((T) item)) );
258                         }
259                 }
260
261                 protected virtual void OnAddingNew (AddingNewEventArgs e)
262                 {
263                         if (AddingNew != null)
264                                 AddingNew (this, e);
265                 }
266
267                 protected virtual void OnListChanged (ListChangedEventArgs e)
268                 {
269                         if (ListChanged != null)
270                                 ListChanged (this, e);
271                 }
272
273                 protected override void RemoveItem (int index)
274                 {
275                         if (!AllowRemove)
276                                 throw new NotSupportedException ();
277
278                         EndNew (pending_add_index);
279                         if (type_raises_item_changed_events) {
280                                 (base[index] as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
281                         }
282                         base.RemoveItem (index);
283
284                         if (raise_list_changed_events)
285                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
286                 }
287
288                 protected virtual void RemoveSortCore ()
289                 {
290                         throw new NotSupportedException ();
291                 }
292
293                 public void ResetBindings ()
294                 {
295                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
296                 }
297
298                 public void ResetItem (int position)
299                 {
300                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, position));
301                 }
302
303                 protected override void SetItem (int index, T item)
304                 {
305                         if (type_raises_item_changed_events) {
306                                 (base[index] as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
307                                 (item as INotifyPropertyChanged).PropertyChanged += Item_PropertyChanged;
308                         }
309                         base.SetItem (index, item);
310
311                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, index));
312                 }
313
314                 void IBindingList.AddIndex (PropertyDescriptor index)
315                 {
316                         /* no implementation by default */
317                 }
318
319                 object IBindingList.AddNew ()
320                 {
321                         return AddNew ();
322                 }
323
324                 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
325                 {
326                         ApplySortCore (property, direction);
327                 }
328
329                 int IBindingList.Find (PropertyDescriptor property, object key)
330                 {
331                         return FindCore (property, key);
332                 }
333
334                 void IBindingList.RemoveIndex (PropertyDescriptor property)
335                 {
336                         /* no implementation by default */
337                 }
338
339                 void IBindingList.RemoveSort ()
340                 {
341                         RemoveSortCore ();
342                 }
343
344                 bool IBindingList.IsSorted {
345                         get { return IsSortedCore; }
346                 }
347
348                 ListSortDirection IBindingList.SortDirection {
349                         get { return SortDirectionCore; }
350                 }
351
352                 PropertyDescriptor IBindingList.SortProperty {
353                         get { return SortPropertyCore; }
354                 }
355
356                 bool IBindingList.AllowEdit {
357                         get { return AllowEdit; }
358                 }
359
360                 bool IBindingList.AllowNew {
361                         get { return AllowNew; }
362                 }
363
364                 bool IBindingList.AllowRemove {
365                         get { return AllowRemove; }
366                 }
367
368                 bool IBindingList.SupportsChangeNotification {
369                         get { return SupportsChangeNotificationCore; }
370                 }
371
372                 bool IBindingList.SupportsSearching {
373                         get { return SupportsSearchingCore; }
374                 }
375
376                 bool IBindingList.SupportsSorting {
377                         get { return SupportsSortingCore; }
378                 }
379
380                 bool IRaiseItemChangedEvents.RaisesItemChangedEvents {
381                         get { return type_raises_item_changed_events; }
382                 }
383         }
384
385 }
386