* BindingContext.cs: Check the binding after its added so that
[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                                 table.Columns.CollectionChanged  += new CollectionChangeEventHandler (MetaDataChangedHandler);
82                                 table.ChildRelations.CollectionChanged  += new CollectionChangeEventHandler (MetaDataChangedHandler);
83                                 table.ParentRelations.CollectionChanged  += new CollectionChangeEventHandler (MetaDataChangedHandler);
84                                 table.Constraints.CollectionChanged += new CollectionChangeEventHandler (MetaDataChangedHandler);
85                         }
86                 }
87
88                 public IList List {
89                         get { return list; }
90                 }
91
92                 public override object Current {
93                         get {
94                                 return list [listposition];
95                         }
96                 }
97
98                 public override int Count {
99                         get { return list.Count; }
100                 }
101
102                 public override int Position {
103                         get {
104                                 return listposition;
105                         } 
106                         set {
107                                 if (value < 0)
108                                         value = 0;
109                                 if (value == list.Count)
110                                         value = list.Count - 1;
111                                 if (listposition == value)
112                                         return;
113                                 listposition = value;
114                                 OnCurrentChanged (EventArgs.Empty);
115                                 OnPositionChanged (EventArgs.Empty);
116                         }
117                 }
118                 
119                 internal string ListName {
120                         get {
121                                 ITypedList typed = list as ITypedList;
122                                 
123                                 if (typed == null) {
124                                         return finalType.Name;
125                                 } else {
126                                         return typed.GetListName (null);
127                                 }
128                         }               
129                 }
130
131                 public override PropertyDescriptorCollection GetItemProperties ()
132                 {
133                         ITypedList typed = list as ITypedList;
134
135                         if (list is Array) {
136                                 Type element = list.GetType ().GetElementType ();
137                                 return TypeDescriptor.GetProperties (element);
138                         }
139
140                         if (typed != null) {
141                                 return typed.GetItemProperties (null);
142                         }
143
144                         PropertyInfo [] props = finalType.GetProperties ();
145                         for (int i = 0; i < props.Length; i++) {
146                                 if (props [i].Name == "Item") {
147                                         Type t = props [i].PropertyType;
148                                         if (t == typeof (object))
149                                                 continue;
150                                         return GetBrowsableProperties (t);
151                                 }
152                         }
153
154                         if (list.Count > 0) {
155                                 return GetBrowsableProperties (list [0].GetType ());
156                         }
157                         
158                         return new PropertyDescriptorCollection (null);
159                 }
160
161                 public override void RemoveAt (int index)
162                 {
163                         list.RemoveAt (index);
164                 }
165
166                 public override void SuspendBinding ()
167                 {
168                         binding_suspended = true;
169                 }
170                 
171                 public override void ResumeBinding ()
172                 {
173                         binding_suspended = false;
174                 }
175
176                 internal override bool IsSuspended {
177                         get { return binding_suspended; }
178                 }
179                 
180                 internal bool CanAddRows {
181                         get {
182                                 if (list as IBindingList == null) {
183                                         return false;
184                                 }
185                                 
186                                 return true;
187                         }
188                 }
189
190                 public override void AddNew ()
191                 {
192                         if (list as IBindingList == null)
193                                 throw new NotSupportedException ();
194                                 
195                         (list as IBindingList).AddNew ();
196                 }
197
198                 public override void CancelCurrentEdit ()
199                 {
200                         IEditableObject editable = Current as IEditableObject;
201
202                         if (editable == null)
203                                 return;
204                         editable.CancelEdit ();
205                         OnItemChanged (new ItemChangedEventArgs (Position));
206                 }
207                 
208                 public override void EndCurrentEdit ()
209                 {
210                         IEditableObject editable = Current as IEditableObject;
211
212                         if (editable == null)
213                                 return;
214                         editable.EndEdit ();
215                 }
216
217                 public void Refresh ()
218                 {
219                         PullData ();
220                 }
221
222                 [MonoTODO ("This is just a guess, as I can't figure out how to test this method")]
223                 protected void CheckEmpty ()
224                 {
225                         if (list == null || list.Count < 1)
226                                 throw new Exception ("List is empty.");
227                                 
228                 }
229
230                 protected internal override void OnCurrentChanged (EventArgs e)
231                 {
232                         PullData ();
233
234                         if (onCurrentChangedHandler != null) {
235                                 onCurrentChangedHandler (this, e);
236                         }
237                 }
238
239                 protected virtual void OnItemChanged (ItemChangedEventArgs e)
240                 {
241                         PushData ();
242
243                         if (ItemChanged != null)
244                                 ItemChanged (this, e);
245                 }
246
247                 protected virtual void OnPositionChanged (EventArgs e)
248                 {
249                         if (onPositionChangedHandler == null)
250                                 return;
251                         onPositionChangedHandler (this, e);
252                 }
253
254                 protected internal override string GetListName (ArrayList accessors)
255                 {
256                         if (list is ITypedList) {
257                                 PropertyDescriptor [] pds;
258                                 pds = new PropertyDescriptor [accessors.Count];
259                                 accessors.CopyTo (pds, 0);
260                                 return ((ITypedList) list).GetListName (pds);
261                         }
262                         return String.Empty;
263                 }
264
265                 [MonoTODO ("Not totally sure how this works, its doesn't seemt to do a pull/push like i originally assumed")]
266                 protected override void UpdateIsBinding ()
267                 {
268                         UpdateItem ();
269
270                         foreach (Binding binding in Bindings)
271                                 binding.UpdateIsBinding ();
272                 }
273
274                 private void UpdateItem ()
275                 {
276                         // Probably should be validating or something here
277                         EndCurrentEdit ();
278                 }
279                 
280                 internal object GetItem (int index)
281                 {
282                         return list [index];
283                 }               
284                 
285                 private PropertyDescriptorCollection GetBrowsableProperties (Type t)
286                 {
287                         Attribute [] att = new System.Attribute [1];
288                         att [0] = new BrowsableAttribute (true);
289                         return TypeDescriptor.GetProperties (t, att);
290                 }
291
292                 private void MetaDataChangedHandler (object sender, CollectionChangeEventArgs e)
293                 {
294                         if (MetaDataChanged != null)
295                                 MetaDataChanged (this, EventArgs.Empty);
296                 }
297
298                 public event ItemChangedEventHandler ItemChanged;
299                 public event EventHandler MetaDataChanged;
300         }
301 }
302