* Binding.cs: Handle null values for Current and BindingContext.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / CurrencyManager.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) 2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24 //
25
26 using System;
27 using System.Data;
28 using System.Reflection;
29 using System.Collections;
30 using System.ComponentModel;
31
32 namespace System.Windows.Forms {
33         [DefaultMember("Item")]
34         public class CurrencyManager : BindingManagerBase {
35
36                 protected Type finalType;
37                 protected int listposition;
38
39                 private IList list;
40                 private bool binding_suspended;
41
42                 internal CurrencyManager (object data_source, string data_member)
43                 {
44                         if (data_source is IList) {
45                                 list = (IList) data_source;
46                         } else if (data_source is IListSource) {
47                                 list = ((IListSource) data_source).GetList ();
48                         } else {
49                                 throw new Exception ("Attempted to create currency manager " +
50                                         "from invalid type: " + data_source.GetType ());
51                         }
52
53                         if (data_source as ArrayList != null) {
54                                 finalType = ((ArrayList)data_source).GetType ();
55                         } else {
56                                 if (data_source as Array != null) {
57                                         finalType = ((Array) data_source).GetType ();
58                                 } else {
59                                         finalType = null;
60                                 }
61                         }
62
63                         DataTable table = data_source as DataTable;
64                         if (table == null && data_source is DataView)
65                                 table = ((DataView) data_source).Table;
66
67                         
68                         if (table == null) {
69                                 DataSet dataset = data_source as DataSet;
70                                 int sp = data_member.IndexOf ('.');
71                                 if (sp != -1) {
72                                         data_member = data_member.Substring (0, sp);
73                                 }
74                                 if (dataset != null) {
75                                         table = dataset.Tables [data_member];
76                                 }
77                         }
78
79                         if (table != null) {
80                                 list = new DataView (table);
81                                 ((DataView) list).ListChanged += new ListChangedEventHandler (ListChangedHandler);
82                                 table.Columns.CollectionChanged  += new CollectionChangeEventHandler (MetaDataChangedHandler);
83                                 table.ChildRelations.CollectionChanged  += new CollectionChangeEventHandler (MetaDataChangedHandler);
84                                 table.ParentRelations.CollectionChanged  += new CollectionChangeEventHandler (MetaDataChangedHandler);
85                                 table.Constraints.CollectionChanged += new CollectionChangeEventHandler (MetaDataChangedHandler);
86                         }
87                 }
88
89                 public IList List {
90                         get { return list; }
91                 }
92
93                 public override object Current {
94                         get {
95                                 if (list.Count == 0)
96                                         return null;
97                                 return list [listposition];
98                         }
99                 }
100
101                 public override int Count {
102                         get { return list.Count; }
103                 }
104
105                 public override int Position {
106                         get {
107                                 return listposition;
108                         } 
109                         set {
110                                 if (value < 0)
111                                         value = 0;
112                                 if (value == list.Count)
113                                         value = list.Count - 1;
114                                 if (listposition == value)
115                                         return;
116                                 listposition = value;
117                                 OnCurrentChanged (EventArgs.Empty);
118                                 OnPositionChanged (EventArgs.Empty);
119                         }
120                 }
121                 
122                 internal string ListName {
123                         get {
124                                 ITypedList typed = list as ITypedList;
125                                 
126                                 if (typed == null) {
127                                         return finalType.Name;
128                                 } else {
129                                         return typed.GetListName (null);
130                                 }
131                         }               
132                 }
133
134                 public override PropertyDescriptorCollection GetItemProperties ()
135                 {
136                         ITypedList typed = list as ITypedList;
137
138                         if (list is Array) {
139                                 Type element = list.GetType ().GetElementType ();
140                                 return TypeDescriptor.GetProperties (element);
141                         }
142
143                         if (typed != null) {
144                                 return typed.GetItemProperties (null);
145                         }
146
147                         PropertyInfo [] props = finalType.GetProperties ();
148                         for (int i = 0; i < props.Length; i++) {
149                                 if (props [i].Name == "Item") {
150                                         Type t = props [i].PropertyType;
151                                         if (t == typeof (object))
152                                                 continue;
153                                         return GetBrowsableProperties (t);
154                                 }
155                         }
156
157                         if (list.Count > 0) {
158                                 return GetBrowsableProperties (list [0].GetType ());
159                         }
160                         
161                         return new PropertyDescriptorCollection (null);
162                 }
163
164                 public override void RemoveAt (int index)
165                 {
166                         list.RemoveAt (index);
167                 }
168
169                 public override void SuspendBinding ()
170                 {
171                         binding_suspended = true;
172                 }
173                 
174                 public override void ResumeBinding ()
175                 {
176                         binding_suspended = false;
177                 }
178
179                 internal override bool IsSuspended {
180                         get { return binding_suspended; }
181                 }
182                 
183                 internal bool CanAddRows {
184                         get {
185                                 if (list as IBindingList == null) {
186                                         return false;
187                                 }
188                                 
189                                 return true;
190                         }
191                 }
192
193                 public override void AddNew ()
194                 {
195                         if (list as IBindingList == null)
196                                 throw new NotSupportedException ();
197                                 
198                         (list as IBindingList).AddNew ();
199                 }
200
201                 public override void CancelCurrentEdit ()
202                 {
203                         IEditableObject editable = Current as IEditableObject;
204
205                         if (editable == null)
206                                 return;
207                         editable.CancelEdit ();
208                         OnItemChanged (new ItemChangedEventArgs (Position));
209                 }
210                 
211                 public override void EndCurrentEdit ()
212                 {
213                         IEditableObject editable = Current as IEditableObject;
214
215                         if (editable == null)
216                                 return;
217                         editable.EndEdit ();
218                 }
219
220                 public void Refresh ()
221                 {
222                         PullData ();
223                 }
224
225                 protected void CheckEmpty ()
226                 {
227                         if (list == null || list.Count < 1)
228                                 throw new Exception ("List is empty.");
229                                 
230                 }
231
232                 protected internal override void OnCurrentChanged (EventArgs e)
233                 {
234                         PullData ();
235
236                         if (onCurrentChangedHandler != null) {
237                                 onCurrentChangedHandler (this, e);
238                         }
239                 }
240
241                 protected virtual void OnItemChanged (ItemChangedEventArgs e)
242                 {
243                         PushData ();
244
245                         if (ItemChanged != null)
246                                 ItemChanged (this, e);
247                 }
248
249                 protected virtual void OnPositionChanged (EventArgs e)
250                 {
251                         if (onPositionChangedHandler == null)
252                                 return;
253                         onPositionChangedHandler (this, e);
254                 }
255
256                 protected internal override string GetListName (ArrayList accessors)
257                 {
258                         if (list is ITypedList) {
259                                 PropertyDescriptor [] pds;
260                                 pds = new PropertyDescriptor [accessors.Count];
261                                 accessors.CopyTo (pds, 0);
262                                 return ((ITypedList) list).GetListName (pds);
263                         }
264                         return String.Empty;
265                 }
266
267                 protected override void UpdateIsBinding ()
268                 {
269                         UpdateItem ();
270
271                         foreach (Binding binding in Bindings)
272                                 binding.UpdateIsBinding ();
273                 }
274
275                 private void UpdateItem ()
276                 {
277                         // Probably should be validating or something here
278                         EndCurrentEdit ();
279                 }
280                 
281                 internal object GetItem (int index)
282                 {
283                         return list [index];
284                 }               
285                 
286                 private PropertyDescriptorCollection GetBrowsableProperties (Type t)
287                 {
288                         Attribute [] att = new System.Attribute [1];
289                         att [0] = new BrowsableAttribute (true);
290                         return TypeDescriptor.GetProperties (t, att);
291                 }
292
293                 private void MetaDataChangedHandler (object sender, CollectionChangeEventArgs e)
294                 {
295                         if (MetaDataChanged != null)
296                                 MetaDataChanged (this, EventArgs.Empty);
297                 }
298
299                 private void ListChangedHandler (object sender, ListChangedEventArgs e)
300                 {
301                         UpdateIsBinding ();
302                 }
303
304                 public event ItemChangedEventHandler ItemChanged;
305                 public event EventHandler MetaDataChanged;
306         }
307 }
308