2008-03-06 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / BindingContext.cs
index 8dacd50dba44a26454f4e03352a0d51ac1ad915d..cc09f64d346882f5dd9dc7638ddc4b983517da90 100644 (file)
@@ -24,6 +24,7 @@
 //     Jackson Harper  jackson@ximian.com
 
 
+using System.Data;
 using System.Collections;
 using System.Globalization;
 using System.ComponentModel;
@@ -35,74 +36,29 @@ namespace System.Windows.Forms {
        public class BindingContext : ICollection, IEnumerable {
 
                private Hashtable managers;
+               private EventHandler onCollectionChangedHandler;
 
-               private class DataSourceEntry {
+               private class HashKey {
+                       public object source;
+                       public string member;
 
-                       private object source;
-                       private Hashtable members;
-                       // private BindingManagerBase default_manager;
-                       
-                       public DataSourceEntry (object source)
+                       public HashKey (object source, string member)
                        {
                                this.source = source;
-                               members = new Hashtable ();
-                       }
-
-                       public BindingManagerBase AddMember (string member)
-                       {
-                               BindingManagerBase res = members [member] as BindingManagerBase;
-                               if (res != null)
-                                       return res;
-                               res = CreateBindingManager (source, member);
-                               members [member] = res;
-                               return res;
-                       }
-
-                       public void AddMember (string member, BindingManagerBase manager)
-                       {
-                               members [member] = manager;
-                       }
-
-                       public bool Contains (string member)
-                       {
-                               return members.Contains (member);
-                       }
-               }
-
-               private class ManagerEntry {
-
-                       private object source;
-                       private WeakReference member_ref;
-                       
-                       private int member_hash;
-
-                       public ManagerEntry (object source, string member)
-                       {
-                               this.source = source;
-                               if (member == null)
-                                       member = String.Empty;
-                               
-                               member_hash = member.ToLower (CultureInfo.InvariantCulture).GetHashCode ();
-                               if (member_hash == 0)
-                                       member_hash = 1;
-                               member_ref = new WeakReference (member, false);
-                       }
-
-                       public override bool Equals (object b)
-                       {
-                               ManagerEntry o = (ManagerEntry) b;
-
-                               return (o.source == source && o.member_ref.Target == member_ref.Target);
+                               this.member = member;
                        }
 
                        public override int GetHashCode ()
                        {
-                               return member_hash * source.GetHashCode ();
+                               return source.GetHashCode() ^ member.GetHashCode ();
                        }
 
-                       public override string ToString ()
+                       public override bool Equals (object o)
                        {
-                               return source.ToString () + " + " + (member_ref.Target == null ? " -- null --" : member_ref.Target.ToString ());
+                               HashKey hk = o as HashKey;
+                               if (hk == null)
+                                       return false;
+                               return hk.source == source && hk.member == member;
                        }
                }
 
@@ -112,39 +68,63 @@ namespace System.Windows.Forms {
                }
 
                public bool IsReadOnly {
-                       get {
-                               return false;
-                       }
+                       get { return false; }
                }
 
                public BindingManagerBase this [object dataSource] {
-                       get {
-                               return this [dataSource, String.Empty];
-                       }
+                       get { return this [dataSource, String.Empty]; }
                }
 
-               public BindingManagerBase this [object data_source, string data_member] {
+               public BindingManagerBase this [object dataSource, string dataMember] {
                        get {
-                               DataSourceEntry ds = managers [data_source] as DataSourceEntry;
-                               if (ds == null) {
-                                       ds = new DataSourceEntry (data_source);
-                                       managers [data_source] = ds;
-                               }
-                               return ds.AddMember (data_member);
+                               if (dataSource == null)
+                                       throw new ArgumentNullException ("dataSource");
+                               if (dataMember == null)
+                                       dataMember = String.Empty;
+
+                               HashKey key = new HashKey (dataSource, dataMember);
+                               BindingManagerBase res = managers [key] as BindingManagerBase;
+
+                               if (res != null)
+                                       return res;
+
+                               res = CreateBindingManager (dataSource, dataMember);
+                               if (res == null)
+                                       return null;
+                               managers [key] = res;
+                               return res;
                        }
                }
 
-               private static BindingManagerBase CreateBindingManager (object data_source, 
-                       string data_member)
+               private BindingManagerBase CreateBindingManager (object data_source, string data_member)
                {
-                       if (data_source is IList || 
-                               data_source is IListSource ||
-                               data_source is IBindingList) {
-                               CurrencyManager res = new CurrencyManager (data_source, data_member);
-                               return res;
+                       if (data_member == "") {
+                               if (IsListType (data_source.GetType ()))
+                                       return new CurrencyManager (data_source);
+                               else
+                                       return new PropertyManager (data_source);
                        }
+                       else {
+                               BindingMemberInfo info = new BindingMemberInfo (data_member);
 
-                       return new PropertyManager (data_source, data_member);
+                               BindingManagerBase parent_manager = this[data_source, info.BindingPath];
+
+                               PropertyDescriptor pd = parent_manager == null ? null : parent_manager.GetItemProperties ().Find (info.BindingField, true);
+
+                               if (pd == null)
+                                       throw new ArgumentException (String.Format ("Cannot create a child list for field {0}.", info.BindingField));
+
+                               if (IsListType (pd.PropertyType))
+                                       return new RelatedCurrencyManager (parent_manager, pd);
+                               else
+                                       return new RelatedPropertyManager (parent_manager, info.BindingField);
+                       }
+               }
+
+               bool IsListType (Type t)
+               {
+                       return (typeof (IList).IsAssignableFrom (t)
+                               || typeof (IListSource).IsAssignableFrom (t));
                }
 
                #region Public Instance Methods
@@ -155,11 +135,13 @@ namespace System.Windows.Forms {
 
                public bool Contains (object dataSource, string dataMember)
                {
-                       DataSourceEntry ds = managers [dataSource] as DataSourceEntry;
-                       if (ds == null)
-                               return false;
-                       return ds.Contains (dataMember);
+                       if (dataSource == null)
+                               throw new ArgumentNullException ("dataSource");
+                       if (dataMember == null)
+                               dataMember = String.Empty;
 
+                       HashKey key = new HashKey (dataSource, dataMember);
+                       return managers [key] != null;
                }
                #endregion      // Public Instance Methods
 
@@ -177,12 +159,9 @@ namespace System.Windows.Forms {
                                throw new ArgumentNullException ("dataSource");
                        if (listManager == null)
                                throw new ArgumentNullException ("listManager");
-                       DataSourceEntry ds = managers [dataSource] as DataSourceEntry;
-                       if (ds == null) {
-                               ds = new DataSourceEntry (dataSource);
-                               managers [dataSource] = ds;
-                       }
-                       ds.AddMember (String.Empty, listManager);
+
+                       HashKey key = new HashKey (dataSource, String.Empty);
+                       managers [key] = listManager;
                }
 
                protected internal void Clear ()
@@ -196,27 +175,43 @@ namespace System.Windows.Forms {
                        managers.Clear ();
                }
 
-               protected virtual void OnCollectionChanged(System.ComponentModel.CollectionChangeEventArgs ccevent)
+               protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
                {
-                       if (CollectionChanged != null) {
-                               CollectionChanged (this, ccevent);
+                       if (onCollectionChangedHandler != null) {
+                               onCollectionChangedHandler (this, ccevent);
                        }
                }
 
                protected internal void Remove (object dataSource)
                {
+                       if (dataSource == null)
+                               throw new ArgumentNullException ("dataSource");
+
                        RemoveCore (dataSource);
                        OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataSource));
                }
 
                protected virtual void RemoveCore (object dataSource)
                {
-                       managers.Remove (dataSource);
+                       HashKey[] keys = new HashKey [managers.Keys.Count];
+                       managers.Keys.CopyTo (keys, 0);
+
+                       for (int i = 0; i < keys.Length; i ++) {
+                               if (keys[i].source == dataSource)
+                                       managers.Remove (keys[i]);
+                       }
                }
                #endregion      // Protected Instance Methods
 
                #region Events
-               public event CollectionChangeEventHandler CollectionChanged;
+#if NET_2_0
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+#endif
+               public event CollectionChangeEventHandler CollectionChanged {
+                       add { throw new NotImplementedException (); }
+                       remove { /* nothing to do here.. */ }
+               }
                #endregion      // Events
 
                #region ICollection Interfaces
@@ -226,35 +221,24 @@ namespace System.Windows.Forms {
                }
 
                int ICollection.Count {
-                       get {
-                               return managers.Count;
-                       }
+                       get { return managers.Count; }
                }
 
                bool ICollection.IsSynchronized {
-                       get {
-                               return false;
-                       }
+                       get { return false; }
                }
 
                object ICollection.SyncRoot {
-                       get {
-                               return null;
-                       }
+                       get { return null; }
                }
 
                #endregion      // ICollection Interfaces
 
                #region IEnumerable Interfaces
-               [MonoTODO]
+               [MonoTODO ("our enumerator is slightly different.  in MS's implementation the Values are WeakReferences to the managers.")]
                IEnumerator IEnumerable.GetEnumerator() {
-                       throw new NotImplementedException();
+                       return managers.GetEnumerator ();
                }
                #endregion      // IEnumerable Interfaces
-
-               private ManagerEntry CreateEntry (object dataSource, string dataMember)
-               {
-                       return new ManagerEntry (dataSource, dataMember);
-               }
        }
 }