* TextBoxBase.cs: Take HideSelection into account when
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / CurrencyManager.cs
blobdb161937840fad8f528c8d0da432cbd967547f43
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.
20 // Copyright (c) 2005 Novell, Inc.
22 // Authors:
23 // Jackson Harper (jackson@ximian.com)
26 using System;
27 using System.Data;
28 using System.Reflection;
29 using System.Collections;
30 using System.ComponentModel;
32 namespace System.Windows.Forms {
33 public class CurrencyManager : BindingManagerBase {
35 protected int listposition;
36 protected Type finalType;
38 private IList list;
39 private bool binding_suspended;
41 private object data_source;
43 bool editing;
45 internal CurrencyManager ()
49 internal CurrencyManager (object data_source)
51 SetDataSource (data_source);
54 public IList List {
55 get { return list; }
58 public override object Current {
59 get {
60 if (listposition == -1 || listposition >= list.Count)
61 throw new IndexOutOfRangeException ("list position");
62 return list [listposition];
66 public override int Count {
67 get { return list.Count; }
70 public override int Position {
71 get {
72 return listposition;
74 set {
75 if (value < 0)
76 value = 0;
77 if (value == list.Count)
78 value = list.Count - 1;
79 if (listposition == value)
80 return;
82 if (listposition != -1)
83 EndCurrentEdit ();
85 listposition = value;
86 OnCurrentChanged (EventArgs.Empty);
87 OnPositionChanged (EventArgs.Empty);
91 internal void SetDataSource (object data_source)
93 if (this.data_source is IBindingList)
94 ((IBindingList)this.data_source).ListChanged -= new ListChangedEventHandler (ListChangedHandler);
96 if (data_source is IListSource)
97 data_source = ((IListSource)data_source).GetList();
99 this.data_source = data_source;
100 if (data_source != null)
101 this.finalType = data_source.GetType();
103 listposition = -1;
104 if (this.data_source is IBindingList)
105 ((IBindingList)this.data_source).ListChanged += new ListChangedEventHandler (ListChangedHandler);
107 list = (IList)data_source;
109 // XXX this is wrong. MS invokes OnItemChanged directly, which seems to call PushData.
110 ListChangedHandler (null, new ListChangedEventArgs (ListChangedType.Reset, -1));
113 public override PropertyDescriptorCollection GetItemProperties ()
115 if (list is Array) {
116 Type element = list.GetType ().GetElementType ();
117 return TypeDescriptor.GetProperties (element);
120 if (list is ITypedList) {
121 return ((ITypedList)list).GetItemProperties (null);
124 PropertyInfo [] props = data_source.GetType().GetProperties ();
125 for (int i = 0; i < props.Length; i++) {
126 if (props [i].Name == "Item") {
127 Type t = props [i].PropertyType;
128 if (t == typeof (object))
129 continue;
130 return GetBrowsableProperties (t);
134 if (list.Count > 0) {
135 return GetBrowsableProperties (list [0].GetType ());
138 return new PropertyDescriptorCollection (null);
141 public override void RemoveAt (int index)
143 list.RemoveAt (index);
146 public override void SuspendBinding ()
148 binding_suspended = true;
151 public override void ResumeBinding ()
153 binding_suspended = false;
156 internal override bool IsSuspended {
157 get { return binding_suspended; }
160 // XXX this needs re-addressing once DataViewManager.AllowNew is implemented
161 internal bool CanAddRows {
162 get {
163 /* if we're readonly, don't even bother checking if we can add new rows */
164 if (list.IsReadOnly)
165 return false;
167 if (list is IBindingList) {
168 return true;
169 //return ((IBindingList)list).AllowNew;
172 return false;
176 public override void AddNew ()
178 if (list as IBindingList == null)
179 throw new NotSupportedException ();
181 (list as IBindingList).AddNew ();
183 EndCurrentEdit ();
185 listposition = list.Count - 1;
187 OnCurrentChanged (EventArgs.Empty);
188 OnPositionChanged (EventArgs.Empty);
192 void BeginEdit ()
194 IEditableObject editable = Current as IEditableObject;
196 if (editable != null) {
197 try {
198 editable.BeginEdit ();
199 editing = true;
201 catch {
202 /* swallow exceptions in IEditableObject.BeginEdit () */
207 public override void CancelCurrentEdit ()
209 if (listposition == -1)
210 return;
212 IEditableObject editable = Current as IEditableObject;
214 if (editable != null) {
215 editing = false;
216 editable.CancelEdit ();
217 OnItemChanged (new ItemChangedEventArgs (Position));
221 public override void EndCurrentEdit ()
223 if (listposition == -1)
224 return;
226 IEditableObject editable = Current as IEditableObject;
228 if (editable != null) {
229 editing = false;
230 editable.EndEdit ();
234 public void Refresh ()
236 ListChangedHandler (null, new ListChangedEventArgs (ListChangedType.Reset, -1));
239 protected void CheckEmpty ()
241 if (list == null || list.Count < 1)
242 throw new Exception ("List is empty.");
246 protected internal override void OnCurrentChanged (EventArgs e)
248 BeginEdit ();
250 if (onCurrentChangedHandler != null) {
251 onCurrentChangedHandler (this, e);
255 protected virtual void OnItemChanged (ItemChangedEventArgs e)
257 if (ItemChanged != null)
258 ItemChanged (this, e);
261 protected virtual void OnPositionChanged (EventArgs e)
263 if (onPositionChangedHandler != null)
264 onPositionChangedHandler (this, e);
267 protected internal override string GetListName (ArrayList accessors)
269 if (list is ITypedList) {
270 PropertyDescriptor [] pds = null;
271 if (accessors != null) {
272 pds = new PropertyDescriptor [accessors.Count];
273 accessors.CopyTo (pds, 0);
275 return ((ITypedList) list).GetListName (pds);
277 else if (finalType != null) {
278 return finalType.Name;
280 return String.Empty;
283 protected override void UpdateIsBinding ()
285 UpdateItem ();
287 foreach (Binding binding in Bindings)
288 binding.UpdateIsBinding ();
291 private void UpdateItem ()
293 // Probably should be validating or something here
294 if (listposition != -1) {
295 EndCurrentEdit ();
297 else if (list.Count > 0) {
299 listposition = 0;
301 BeginEdit ();
305 internal object this [int index] {
306 get { return list [index]; }
309 private PropertyDescriptorCollection GetBrowsableProperties (Type t)
311 Attribute [] att = new System.Attribute [1];
312 att [0] = new BrowsableAttribute (true);
313 return TypeDescriptor.GetProperties (t, att);
316 private void OnMetaDataChanged (EventArgs args)
318 if (MetaDataChanged != null)
319 MetaDataChanged (this, args);
322 private void ListChangedHandler (object sender, ListChangedEventArgs e)
324 switch (e.ListChangedType) {
325 case ListChangedType.PropertyDescriptorAdded:
326 case ListChangedType.PropertyDescriptorDeleted:
327 case ListChangedType.PropertyDescriptorChanged:
328 OnMetaDataChanged (EventArgs.Empty);
329 break;
330 case ListChangedType.ItemDeleted:
331 if (listposition == e.NewIndex) {
332 listposition = e.NewIndex - 1;
333 OnCurrentChanged (EventArgs.Empty);
334 OnPositionChanged (EventArgs.Empty);
337 OnItemChanged (new ItemChangedEventArgs (-1));
338 break;
339 case ListChangedType.ItemAdded:
340 if (listposition == -1) {
341 /* do we need this logic up above in ItemDeleted as well? */
342 listposition = e.NewIndex == 0 ? 0 : e.NewIndex - 1;
343 OnCurrentChanged (EventArgs.Empty);
344 OnPositionChanged (EventArgs.Empty);
347 OnItemChanged (new ItemChangedEventArgs (-1));
348 break;
349 case ListChangedType.ItemChanged:
350 if (editing)
351 OnItemChanged (new ItemChangedEventArgs (e.NewIndex));
352 break;
353 default:
354 PushData ();
355 OnItemChanged (new ItemChangedEventArgs (-1));
356 // UpdateIsBinding ();
357 break;
361 public event ItemChangedEventHandler ItemChanged;
362 public event EventHandler MetaDataChanged;